@mastra/libsql 0.0.0-bundle-recursion-20251030002519 → 0.0.0-bundle-studio-cloud-20251222034739
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 +861 -3
- package/README.md +30 -20
- package/dist/index.cjs +2098 -1668
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2032 -1602
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +259 -0
- package/dist/storage/db/index.d.ts.map +1 -0
- package/dist/storage/{domains → db}/utils.d.ts +4 -0
- package/dist/storage/db/utils.d.ts.map +1 -0
- package/dist/storage/domains/agents/index.d.ts +23 -0
- package/dist/storage/domains/agents/index.d.ts.map +1 -0
- package/dist/storage/domains/memory/index.d.ts +19 -53
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts +17 -17
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +15 -14
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/dist/storage/domains/workflows/index.d.ts +18 -32
- package/dist/storage/domains/workflows/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +70 -128
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts +7 -3
- package/dist/vector/index.d.ts.map +1 -1
- package/dist/vector/sql-builder.d.ts.map +1 -1
- package/package.json +12 -8
- package/dist/storage/domains/legacy-evals/index.d.ts +0 -18
- package/dist/storage/domains/legacy-evals/index.d.ts.map +0 -1
- package/dist/storage/domains/operations/index.d.ts +0 -110
- package/dist/storage/domains/operations/index.d.ts.map +0 -1
- package/dist/storage/domains/utils.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
var client = require('@libsql/client');
|
|
4
4
|
var error = require('@mastra/core/error');
|
|
5
|
+
var storage = require('@mastra/core/storage');
|
|
5
6
|
var utils = require('@mastra/core/utils');
|
|
6
7
|
var vector = require('@mastra/core/vector');
|
|
7
8
|
var filter = require('@mastra/core/vector/filter');
|
|
8
|
-
var
|
|
9
|
+
var base = require('@mastra/core/base');
|
|
9
10
|
var agent = require('@mastra/core/agent');
|
|
10
|
-
var
|
|
11
|
+
var evals = require('@mastra/core/evals');
|
|
11
12
|
|
|
12
13
|
// src/vector/index.ts
|
|
13
14
|
var LibSQLFilterTranslator = class extends filter.BaseFilterTranslator {
|
|
@@ -92,12 +93,20 @@ var createBasicOperator = (symbol) => {
|
|
|
92
93
|
};
|
|
93
94
|
};
|
|
94
95
|
var createNumericOperator = (symbol) => {
|
|
95
|
-
return (key) => {
|
|
96
|
+
return (key, value) => {
|
|
96
97
|
const jsonPath = getJsonPath(key);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
const isNumeric = typeof value === "number" || typeof value === "string" && !isNaN(Number(value)) && value.trim() !== "";
|
|
99
|
+
if (isNumeric) {
|
|
100
|
+
return {
|
|
101
|
+
sql: `CAST(json_extract(metadata, ${jsonPath}) AS NUMERIC) ${symbol} ?`,
|
|
102
|
+
needsValue: true
|
|
103
|
+
};
|
|
104
|
+
} else {
|
|
105
|
+
return {
|
|
106
|
+
sql: `CAST(json_extract(metadata, ${jsonPath}) AS TEXT) ${symbol} ?`,
|
|
107
|
+
needsValue: true
|
|
108
|
+
};
|
|
109
|
+
}
|
|
101
110
|
};
|
|
102
111
|
};
|
|
103
112
|
var validateJsonArray = (key) => {
|
|
@@ -507,9 +516,10 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
507
516
|
syncUrl,
|
|
508
517
|
syncInterval,
|
|
509
518
|
maxRetries = 5,
|
|
510
|
-
initialBackoffMs = 100
|
|
519
|
+
initialBackoffMs = 100,
|
|
520
|
+
id
|
|
511
521
|
}) {
|
|
512
|
-
super();
|
|
522
|
+
super({ id });
|
|
513
523
|
this.turso = client.createClient({
|
|
514
524
|
url: connectionUrl,
|
|
515
525
|
syncUrl,
|
|
@@ -574,7 +584,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
574
584
|
} catch (error$1) {
|
|
575
585
|
throw new error.MastraError(
|
|
576
586
|
{
|
|
577
|
-
id: "
|
|
587
|
+
id: storage.createVectorErrorId("LIBSQL", "QUERY", "INVALID_ARGS"),
|
|
578
588
|
domain: error.ErrorDomain.STORAGE,
|
|
579
589
|
category: error.ErrorCategory.USER
|
|
580
590
|
},
|
|
@@ -616,7 +626,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
616
626
|
} catch (error$1) {
|
|
617
627
|
throw new error.MastraError(
|
|
618
628
|
{
|
|
619
|
-
id: "
|
|
629
|
+
id: storage.createVectorErrorId("LIBSQL", "QUERY", "FAILED"),
|
|
620
630
|
domain: error.ErrorDomain.STORAGE,
|
|
621
631
|
category: error.ErrorCategory.THIRD_PARTY
|
|
622
632
|
},
|
|
@@ -630,7 +640,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
630
640
|
} catch (error$1) {
|
|
631
641
|
throw new error.MastraError(
|
|
632
642
|
{
|
|
633
|
-
id: "
|
|
643
|
+
id: storage.createVectorErrorId("LIBSQL", "UPSERT", "FAILED"),
|
|
634
644
|
domain: error.ErrorDomain.STORAGE,
|
|
635
645
|
category: error.ErrorCategory.THIRD_PARTY
|
|
636
646
|
},
|
|
@@ -684,7 +694,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
684
694
|
} catch (error$1) {
|
|
685
695
|
throw new error.MastraError(
|
|
686
696
|
{
|
|
687
|
-
id: "
|
|
697
|
+
id: storage.createVectorErrorId("LIBSQL", "CREATE_INDEX", "FAILED"),
|
|
688
698
|
domain: error.ErrorDomain.STORAGE,
|
|
689
699
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
690
700
|
details: { indexName: args.indexName, dimension: args.dimension }
|
|
@@ -723,7 +733,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
723
733
|
} catch (error$1) {
|
|
724
734
|
throw new error.MastraError(
|
|
725
735
|
{
|
|
726
|
-
id: "
|
|
736
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_INDEX", "FAILED"),
|
|
727
737
|
domain: error.ErrorDomain.STORAGE,
|
|
728
738
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
729
739
|
details: { indexName: args.indexName }
|
|
@@ -754,7 +764,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
754
764
|
} catch (error$1) {
|
|
755
765
|
throw new error.MastraError(
|
|
756
766
|
{
|
|
757
|
-
id: "
|
|
767
|
+
id: storage.createVectorErrorId("LIBSQL", "LIST_INDEXES", "FAILED"),
|
|
758
768
|
domain: error.ErrorDomain.STORAGE,
|
|
759
769
|
category: error.ErrorCategory.THIRD_PARTY
|
|
760
770
|
},
|
|
@@ -802,7 +812,7 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
802
812
|
} catch (e) {
|
|
803
813
|
throw new error.MastraError(
|
|
804
814
|
{
|
|
805
|
-
id: "
|
|
815
|
+
id: storage.createVectorErrorId("LIBSQL", "DESCRIBE_INDEX", "FAILED"),
|
|
806
816
|
domain: error.ErrorDomain.STORAGE,
|
|
807
817
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
808
818
|
details: { indexName }
|
|
@@ -825,8 +835,27 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
825
835
|
updateVector(args) {
|
|
826
836
|
return this.executeWriteOperationWithRetry(() => this.doUpdateVector(args));
|
|
827
837
|
}
|
|
828
|
-
async doUpdateVector(
|
|
838
|
+
async doUpdateVector(params) {
|
|
839
|
+
const { indexName, update } = params;
|
|
829
840
|
const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
|
|
841
|
+
if ("id" in params && params.id && "filter" in params && params.filter) {
|
|
842
|
+
throw new error.MastraError({
|
|
843
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "MUTUALLY_EXCLUSIVE"),
|
|
844
|
+
domain: error.ErrorDomain.STORAGE,
|
|
845
|
+
category: error.ErrorCategory.USER,
|
|
846
|
+
details: { indexName },
|
|
847
|
+
text: "id and filter are mutually exclusive - provide only one"
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
if (!update.vector && !update.metadata) {
|
|
851
|
+
throw new error.MastraError({
|
|
852
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "NO_PAYLOAD"),
|
|
853
|
+
domain: error.ErrorDomain.STORAGE,
|
|
854
|
+
category: error.ErrorCategory.USER,
|
|
855
|
+
details: { indexName },
|
|
856
|
+
text: "No updates provided"
|
|
857
|
+
});
|
|
858
|
+
}
|
|
830
859
|
const updates = [];
|
|
831
860
|
const args = [];
|
|
832
861
|
if (update.vector) {
|
|
@@ -838,32 +867,81 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
838
867
|
args.push(JSON.stringify(update.metadata));
|
|
839
868
|
}
|
|
840
869
|
if (updates.length === 0) {
|
|
870
|
+
return;
|
|
871
|
+
}
|
|
872
|
+
let whereClause;
|
|
873
|
+
let whereValues;
|
|
874
|
+
if ("id" in params && params.id) {
|
|
875
|
+
whereClause = "vector_id = ?";
|
|
876
|
+
whereValues = [params.id];
|
|
877
|
+
} else if ("filter" in params && params.filter) {
|
|
878
|
+
const filter = params.filter;
|
|
879
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
880
|
+
throw new error.MastraError({
|
|
881
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "EMPTY_FILTER"),
|
|
882
|
+
domain: error.ErrorDomain.STORAGE,
|
|
883
|
+
category: error.ErrorCategory.USER,
|
|
884
|
+
details: { indexName },
|
|
885
|
+
text: "Cannot update with empty filter"
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
const translatedFilter = this.transformFilter(filter);
|
|
889
|
+
const { sql: filterSql, values: filterValues } = buildFilterQuery(translatedFilter);
|
|
890
|
+
if (!filterSql || filterSql.trim() === "") {
|
|
891
|
+
throw new error.MastraError({
|
|
892
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "INVALID_FILTER"),
|
|
893
|
+
domain: error.ErrorDomain.STORAGE,
|
|
894
|
+
category: error.ErrorCategory.USER,
|
|
895
|
+
details: { indexName },
|
|
896
|
+
text: "Filter produced empty WHERE clause"
|
|
897
|
+
});
|
|
898
|
+
}
|
|
899
|
+
const normalizedCondition = filterSql.replace(/^\s*WHERE\s+/i, "").trim().toLowerCase();
|
|
900
|
+
const matchAllPatterns = ["true", "1 = 1", "1=1"];
|
|
901
|
+
if (matchAllPatterns.includes(normalizedCondition)) {
|
|
902
|
+
throw new error.MastraError({
|
|
903
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "MATCH_ALL_FILTER"),
|
|
904
|
+
domain: error.ErrorDomain.STORAGE,
|
|
905
|
+
category: error.ErrorCategory.USER,
|
|
906
|
+
details: { indexName, filterSql: normalizedCondition },
|
|
907
|
+
text: "Filter matches all vectors. Provide a specific filter to update targeted vectors."
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
whereClause = filterSql.replace(/^WHERE\s+/i, "");
|
|
911
|
+
whereValues = filterValues;
|
|
912
|
+
} else {
|
|
841
913
|
throw new error.MastraError({
|
|
842
|
-
id: "
|
|
914
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "NO_TARGET"),
|
|
843
915
|
domain: error.ErrorDomain.STORAGE,
|
|
844
916
|
category: error.ErrorCategory.USER,
|
|
845
|
-
details: { indexName
|
|
846
|
-
text: "
|
|
917
|
+
details: { indexName },
|
|
918
|
+
text: "Either id or filter must be provided"
|
|
847
919
|
});
|
|
848
920
|
}
|
|
849
|
-
args.push(id);
|
|
850
921
|
const query = `
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
922
|
+
UPDATE ${parsedIndexName}
|
|
923
|
+
SET ${updates.join(", ")}
|
|
924
|
+
WHERE ${whereClause};
|
|
925
|
+
`;
|
|
855
926
|
try {
|
|
856
927
|
await this.turso.execute({
|
|
857
928
|
sql: query,
|
|
858
|
-
args
|
|
929
|
+
args: [...args, ...whereValues]
|
|
859
930
|
});
|
|
860
931
|
} catch (error$1) {
|
|
932
|
+
const errorDetails = { indexName };
|
|
933
|
+
if ("id" in params && params.id) {
|
|
934
|
+
errorDetails.id = params.id;
|
|
935
|
+
}
|
|
936
|
+
if ("filter" in params && params.filter) {
|
|
937
|
+
errorDetails.filter = JSON.stringify(params.filter);
|
|
938
|
+
}
|
|
861
939
|
throw new error.MastraError(
|
|
862
940
|
{
|
|
863
|
-
id: "
|
|
941
|
+
id: storage.createVectorErrorId("LIBSQL", "UPDATE_VECTOR", "FAILED"),
|
|
864
942
|
domain: error.ErrorDomain.STORAGE,
|
|
865
943
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
866
|
-
details:
|
|
944
|
+
details: errorDetails
|
|
867
945
|
},
|
|
868
946
|
error$1
|
|
869
947
|
);
|
|
@@ -882,10 +960,13 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
882
960
|
} catch (error$1) {
|
|
883
961
|
throw new error.MastraError(
|
|
884
962
|
{
|
|
885
|
-
id: "
|
|
963
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTOR", "FAILED"),
|
|
886
964
|
domain: error.ErrorDomain.STORAGE,
|
|
887
965
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
888
|
-
details: {
|
|
966
|
+
details: {
|
|
967
|
+
indexName: args.indexName,
|
|
968
|
+
...args.id && { id: args.id }
|
|
969
|
+
}
|
|
889
970
|
},
|
|
890
971
|
error$1
|
|
891
972
|
);
|
|
@@ -898,13 +979,107 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
898
979
|
args: [id]
|
|
899
980
|
});
|
|
900
981
|
}
|
|
982
|
+
deleteVectors(args) {
|
|
983
|
+
return this.executeWriteOperationWithRetry(() => this.doDeleteVectors(args));
|
|
984
|
+
}
|
|
985
|
+
async doDeleteVectors({ indexName, filter, ids }) {
|
|
986
|
+
const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
|
|
987
|
+
if (!filter && !ids) {
|
|
988
|
+
throw new error.MastraError({
|
|
989
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "NO_TARGET"),
|
|
990
|
+
domain: error.ErrorDomain.STORAGE,
|
|
991
|
+
category: error.ErrorCategory.USER,
|
|
992
|
+
details: { indexName },
|
|
993
|
+
text: "Either filter or ids must be provided"
|
|
994
|
+
});
|
|
995
|
+
}
|
|
996
|
+
if (filter && ids) {
|
|
997
|
+
throw new error.MastraError({
|
|
998
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "MUTUALLY_EXCLUSIVE"),
|
|
999
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1000
|
+
category: error.ErrorCategory.USER,
|
|
1001
|
+
details: { indexName },
|
|
1002
|
+
text: "Cannot provide both filter and ids - they are mutually exclusive"
|
|
1003
|
+
});
|
|
1004
|
+
}
|
|
1005
|
+
let query;
|
|
1006
|
+
let values;
|
|
1007
|
+
if (ids) {
|
|
1008
|
+
if (ids.length === 0) {
|
|
1009
|
+
throw new error.MastraError({
|
|
1010
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "EMPTY_IDS"),
|
|
1011
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1012
|
+
category: error.ErrorCategory.USER,
|
|
1013
|
+
details: { indexName },
|
|
1014
|
+
text: "Cannot delete with empty ids array"
|
|
1015
|
+
});
|
|
1016
|
+
}
|
|
1017
|
+
const placeholders = ids.map(() => "?").join(", ");
|
|
1018
|
+
query = `DELETE FROM ${parsedIndexName} WHERE vector_id IN (${placeholders})`;
|
|
1019
|
+
values = ids;
|
|
1020
|
+
} else {
|
|
1021
|
+
if (!filter || Object.keys(filter).length === 0) {
|
|
1022
|
+
throw new error.MastraError({
|
|
1023
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "EMPTY_FILTER"),
|
|
1024
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1025
|
+
category: error.ErrorCategory.USER,
|
|
1026
|
+
details: { indexName },
|
|
1027
|
+
text: "Cannot delete with empty filter. Use deleteIndex to delete all vectors."
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
const translatedFilter = this.transformFilter(filter);
|
|
1031
|
+
const { sql: filterSql, values: filterValues } = buildFilterQuery(translatedFilter);
|
|
1032
|
+
if (!filterSql || filterSql.trim() === "") {
|
|
1033
|
+
throw new error.MastraError({
|
|
1034
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "INVALID_FILTER"),
|
|
1035
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1036
|
+
category: error.ErrorCategory.USER,
|
|
1037
|
+
details: { indexName },
|
|
1038
|
+
text: "Filter produced empty WHERE clause"
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
const normalizedCondition = filterSql.replace(/^\s*WHERE\s+/i, "").trim().toLowerCase();
|
|
1042
|
+
const matchAllPatterns = ["true", "1 = 1", "1=1"];
|
|
1043
|
+
if (matchAllPatterns.includes(normalizedCondition)) {
|
|
1044
|
+
throw new error.MastraError({
|
|
1045
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "MATCH_ALL_FILTER"),
|
|
1046
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1047
|
+
category: error.ErrorCategory.USER,
|
|
1048
|
+
details: { indexName, filterSql: normalizedCondition },
|
|
1049
|
+
text: "Filter matches all vectors. Use deleteIndex to delete all vectors from an index."
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
query = `DELETE FROM ${parsedIndexName} ${filterSql}`;
|
|
1053
|
+
values = filterValues;
|
|
1054
|
+
}
|
|
1055
|
+
try {
|
|
1056
|
+
await this.turso.execute({
|
|
1057
|
+
sql: query,
|
|
1058
|
+
args: values
|
|
1059
|
+
});
|
|
1060
|
+
} catch (error$1) {
|
|
1061
|
+
throw new error.MastraError(
|
|
1062
|
+
{
|
|
1063
|
+
id: storage.createVectorErrorId("LIBSQL", "DELETE_VECTORS", "FAILED"),
|
|
1064
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1065
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1066
|
+
details: {
|
|
1067
|
+
indexName,
|
|
1068
|
+
...filter && { filter: JSON.stringify(filter) },
|
|
1069
|
+
...ids && { idsCount: ids.length }
|
|
1070
|
+
}
|
|
1071
|
+
},
|
|
1072
|
+
error$1
|
|
1073
|
+
);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
901
1076
|
truncateIndex(args) {
|
|
902
1077
|
try {
|
|
903
1078
|
return this.executeWriteOperationWithRetry(() => this._doTruncateIndex(args));
|
|
904
1079
|
} catch (error$1) {
|
|
905
1080
|
throw new error.MastraError(
|
|
906
1081
|
{
|
|
907
|
-
id: "
|
|
1082
|
+
id: storage.createVectorErrorId("LIBSQL", "TRUNCATE_INDEX", "FAILED"),
|
|
908
1083
|
domain: error.ErrorDomain.STORAGE,
|
|
909
1084
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
910
1085
|
details: { indexName: args.indexName }
|
|
@@ -920,1694 +1095,1989 @@ var LibSQLVector = class extends vector.MastraVector {
|
|
|
920
1095
|
});
|
|
921
1096
|
}
|
|
922
1097
|
};
|
|
923
|
-
function
|
|
924
|
-
|
|
925
|
-
const testInfoValue = row.test_info ? JSON.parse(row.test_info) : void 0;
|
|
926
|
-
if (!resultValue || typeof resultValue !== "object" || !("score" in resultValue)) {
|
|
927
|
-
throw new Error(`Invalid MetricResult format: ${JSON.stringify(resultValue)}`);
|
|
928
|
-
}
|
|
929
|
-
return {
|
|
930
|
-
input: row.input,
|
|
931
|
-
output: row.output,
|
|
932
|
-
result: resultValue,
|
|
933
|
-
agentName: row.agent_name,
|
|
934
|
-
metricName: row.metric_name,
|
|
935
|
-
instructions: row.instructions,
|
|
936
|
-
testInfo: testInfoValue,
|
|
937
|
-
globalRunId: row.global_run_id,
|
|
938
|
-
runId: row.run_id,
|
|
939
|
-
createdAt: row.created_at
|
|
940
|
-
};
|
|
1098
|
+
function isLockError(error) {
|
|
1099
|
+
return 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");
|
|
941
1100
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
1101
|
+
function createExecuteWriteOperationWithRetry({
|
|
1102
|
+
logger,
|
|
1103
|
+
maxRetries,
|
|
1104
|
+
initialBackoffMs
|
|
1105
|
+
}) {
|
|
1106
|
+
return async function executeWriteOperationWithRetry(operationFn, operationDescription) {
|
|
1107
|
+
let attempts = 0;
|
|
1108
|
+
let backoff = initialBackoffMs;
|
|
1109
|
+
while (attempts < maxRetries) {
|
|
1110
|
+
try {
|
|
1111
|
+
return await operationFn();
|
|
1112
|
+
} catch (error) {
|
|
1113
|
+
logger.debug(`LibSQLStore: Error caught in retry loop for ${operationDescription}`, {
|
|
1114
|
+
errorType: error.constructor.name,
|
|
1115
|
+
errorCode: error.code,
|
|
1116
|
+
errorMessage: error.message,
|
|
1117
|
+
attempts,
|
|
1118
|
+
maxRetries
|
|
1119
|
+
});
|
|
1120
|
+
if (isLockError(error)) {
|
|
1121
|
+
attempts++;
|
|
1122
|
+
if (attempts >= maxRetries) {
|
|
1123
|
+
logger.error(
|
|
1124
|
+
`LibSQLStore: Operation failed after ${maxRetries} attempts due to database lock: ${error.message}`,
|
|
1125
|
+
{ error, attempts, maxRetries }
|
|
1126
|
+
);
|
|
1127
|
+
throw error;
|
|
1128
|
+
}
|
|
1129
|
+
logger.warn(
|
|
1130
|
+
`LibSQLStore: Attempt ${attempts} failed due to database lock during ${operationDescription}. Retrying in ${backoff}ms...`,
|
|
1131
|
+
{ errorMessage: error.message, attempts, backoff, maxRetries }
|
|
1132
|
+
);
|
|
1133
|
+
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
1134
|
+
backoff *= 2;
|
|
1135
|
+
} else {
|
|
1136
|
+
logger.error(`LibSQLStore: Non-lock error during ${operationDescription}, not retrying`, { error });
|
|
1137
|
+
throw error;
|
|
1138
|
+
}
|
|
961
1139
|
}
|
|
962
|
-
throw new error.MastraError(
|
|
963
|
-
{
|
|
964
|
-
id: "LIBSQL_STORE_GET_EVALS_BY_AGENT_NAME_FAILED",
|
|
965
|
-
domain: error.ErrorDomain.STORAGE,
|
|
966
|
-
category: error.ErrorCategory.THIRD_PARTY,
|
|
967
|
-
details: { agentName }
|
|
968
|
-
},
|
|
969
|
-
error$1
|
|
970
|
-
);
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
async getEvals(options = {}) {
|
|
974
|
-
const { agentName, type, page = 0, perPage = 100, dateRange } = options;
|
|
975
|
-
const fromDate = dateRange?.start;
|
|
976
|
-
const toDate = dateRange?.end;
|
|
977
|
-
const conditions = [];
|
|
978
|
-
const queryParams = [];
|
|
979
|
-
if (agentName) {
|
|
980
|
-
conditions.push(`agent_name = ?`);
|
|
981
|
-
queryParams.push(agentName);
|
|
982
|
-
}
|
|
983
|
-
if (type === "test") {
|
|
984
|
-
conditions.push(`(test_info IS NOT NULL AND json_extract(test_info, '$.testPath') IS NOT NULL)`);
|
|
985
|
-
} else if (type === "live") {
|
|
986
|
-
conditions.push(`(test_info IS NULL OR json_extract(test_info, '$.testPath') IS NULL)`);
|
|
987
1140
|
}
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1141
|
+
throw new Error(`LibSQLStore: Unexpected exit from retry loop for ${operationDescription}`);
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
function prepareStatement({ tableName, record }) {
|
|
1145
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1146
|
+
const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1147
|
+
const values = Object.values(record).map((v) => {
|
|
1148
|
+
if (typeof v === `undefined` || v === null) {
|
|
1149
|
+
return null;
|
|
995
1150
|
}
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
const countResult = await this.client.execute({
|
|
999
|
-
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_EVALS} ${whereClause}`,
|
|
1000
|
-
args: queryParams
|
|
1001
|
-
});
|
|
1002
|
-
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
1003
|
-
const currentOffset = page * perPage;
|
|
1004
|
-
const hasMore = currentOffset + perPage < total;
|
|
1005
|
-
if (total === 0) {
|
|
1006
|
-
return {
|
|
1007
|
-
evals: [],
|
|
1008
|
-
total: 0,
|
|
1009
|
-
page,
|
|
1010
|
-
perPage,
|
|
1011
|
-
hasMore: false
|
|
1012
|
-
};
|
|
1013
|
-
}
|
|
1014
|
-
const dataResult = await this.client.execute({
|
|
1015
|
-
sql: `SELECT * FROM ${storage.TABLE_EVALS} ${whereClause} ORDER BY created_at DESC LIMIT ? OFFSET ?`,
|
|
1016
|
-
args: [...queryParams, perPage, currentOffset]
|
|
1017
|
-
});
|
|
1018
|
-
return {
|
|
1019
|
-
evals: dataResult.rows?.map((row) => transformEvalRow(row)) ?? [],
|
|
1020
|
-
total,
|
|
1021
|
-
page,
|
|
1022
|
-
perPage,
|
|
1023
|
-
hasMore
|
|
1024
|
-
};
|
|
1025
|
-
} catch (error$1) {
|
|
1026
|
-
throw new error.MastraError(
|
|
1027
|
-
{
|
|
1028
|
-
id: "LIBSQL_STORE_GET_EVALS_FAILED",
|
|
1029
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1030
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1031
|
-
},
|
|
1032
|
-
error$1
|
|
1033
|
-
);
|
|
1151
|
+
if (v instanceof Date) {
|
|
1152
|
+
return v.toISOString();
|
|
1034
1153
|
}
|
|
1154
|
+
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
1155
|
+
});
|
|
1156
|
+
const placeholders = values.map(() => "?").join(", ");
|
|
1157
|
+
return {
|
|
1158
|
+
sql: `INSERT OR REPLACE INTO ${parsedTableName} (${columns.join(", ")}) VALUES (${placeholders})`,
|
|
1159
|
+
args: values
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
function prepareUpdateStatement({
|
|
1163
|
+
tableName,
|
|
1164
|
+
updates,
|
|
1165
|
+
keys
|
|
1166
|
+
}) {
|
|
1167
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1168
|
+
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
1169
|
+
const updateColumns = Object.keys(updates).map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1170
|
+
const updateValues = Object.values(updates).map(transformToSqlValue);
|
|
1171
|
+
const setClause = updateColumns.map((col) => `${col} = ?`).join(", ");
|
|
1172
|
+
const whereClause = prepareWhereClause(keys, schema);
|
|
1173
|
+
return {
|
|
1174
|
+
sql: `UPDATE ${parsedTableName} SET ${setClause}${whereClause.sql}`,
|
|
1175
|
+
args: [...updateValues, ...whereClause.args]
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
function transformToSqlValue(value) {
|
|
1179
|
+
if (typeof value === "undefined" || value === null) {
|
|
1180
|
+
return null;
|
|
1035
1181
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
client;
|
|
1039
|
-
operations;
|
|
1040
|
-
constructor({ client, operations }) {
|
|
1041
|
-
super();
|
|
1042
|
-
this.client = client;
|
|
1043
|
-
this.operations = operations;
|
|
1182
|
+
if (value instanceof Date) {
|
|
1183
|
+
return value.toISOString();
|
|
1044
1184
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1185
|
+
return typeof value === "object" ? JSON.stringify(value) : value;
|
|
1186
|
+
}
|
|
1187
|
+
function prepareDeleteStatement({ tableName, keys }) {
|
|
1188
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1189
|
+
const whereClause = prepareWhereClause(keys, storage.TABLE_SCHEMAS[tableName]);
|
|
1190
|
+
return {
|
|
1191
|
+
sql: `DELETE FROM ${parsedTableName}${whereClause.sql}`,
|
|
1192
|
+
args: whereClause.args
|
|
1193
|
+
};
|
|
1194
|
+
}
|
|
1195
|
+
function prepareWhereClause(filters, schema) {
|
|
1196
|
+
const conditions = [];
|
|
1197
|
+
const args = [];
|
|
1198
|
+
for (const [columnName, filterValue] of Object.entries(filters)) {
|
|
1199
|
+
const column = schema[columnName];
|
|
1200
|
+
if (!column) {
|
|
1201
|
+
throw new Error(`Unknown column: ${columnName}`);
|
|
1050
1202
|
}
|
|
1051
|
-
const
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
createdAt: new Date(row.createdAt),
|
|
1056
|
-
threadId: row.thread_id,
|
|
1057
|
-
resourceId: row.resourceId
|
|
1058
|
-
};
|
|
1059
|
-
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
1060
|
-
return result;
|
|
1203
|
+
const parsedColumn = utils.parseSqlIdentifier(columnName, "column name");
|
|
1204
|
+
const result = buildCondition2(parsedColumn, filterValue);
|
|
1205
|
+
conditions.push(result.condition);
|
|
1206
|
+
args.push(...result.args);
|
|
1061
1207
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1208
|
+
return {
|
|
1209
|
+
sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
|
|
1210
|
+
args
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
function buildCondition2(columnName, filterValue) {
|
|
1214
|
+
if (filterValue === null) {
|
|
1215
|
+
return { condition: `${columnName} IS NULL`, args: [] };
|
|
1216
|
+
}
|
|
1217
|
+
if (typeof filterValue === "object" && filterValue !== null && ("startAt" in filterValue || "endAt" in filterValue)) {
|
|
1218
|
+
return buildDateRangeCondition(columnName, filterValue);
|
|
1219
|
+
}
|
|
1220
|
+
return {
|
|
1221
|
+
condition: `${columnName} = ?`,
|
|
1222
|
+
args: [transformToSqlValue(filterValue)]
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
function buildDateRangeCondition(columnName, range) {
|
|
1226
|
+
const conditions = [];
|
|
1227
|
+
const args = [];
|
|
1228
|
+
if (range.startAt !== void 0) {
|
|
1229
|
+
conditions.push(`${columnName} >= ?`);
|
|
1230
|
+
args.push(transformToSqlValue(range.startAt));
|
|
1231
|
+
}
|
|
1232
|
+
if (range.endAt !== void 0) {
|
|
1233
|
+
conditions.push(`${columnName} <= ?`);
|
|
1234
|
+
args.push(transformToSqlValue(range.endAt));
|
|
1235
|
+
}
|
|
1236
|
+
if (conditions.length === 0) {
|
|
1237
|
+
throw new Error("Date range must specify at least startAt or endAt");
|
|
1238
|
+
}
|
|
1239
|
+
return {
|
|
1240
|
+
condition: conditions.join(" AND "),
|
|
1241
|
+
args
|
|
1242
|
+
};
|
|
1243
|
+
}
|
|
1244
|
+
function buildDateRangeFilter(dateRange, columnName = "createdAt") {
|
|
1245
|
+
if (!dateRange?.start && !dateRange?.end) {
|
|
1246
|
+
return {};
|
|
1247
|
+
}
|
|
1248
|
+
const filter = {};
|
|
1249
|
+
if (dateRange.start) {
|
|
1250
|
+
filter.startAt = new Date(dateRange.start).toISOString();
|
|
1251
|
+
}
|
|
1252
|
+
if (dateRange.end) {
|
|
1253
|
+
filter.endAt = new Date(dateRange.end).toISOString();
|
|
1254
|
+
}
|
|
1255
|
+
return { [columnName]: filter };
|
|
1256
|
+
}
|
|
1257
|
+
function transformFromSqlRow({
|
|
1258
|
+
tableName,
|
|
1259
|
+
sqlRow
|
|
1260
|
+
}) {
|
|
1261
|
+
const result = {};
|
|
1262
|
+
const jsonColumns = new Set(
|
|
1263
|
+
Object.keys(storage.TABLE_SCHEMAS[tableName]).filter((key) => storage.TABLE_SCHEMAS[tableName][key].type === "jsonb").map((key) => key)
|
|
1264
|
+
);
|
|
1265
|
+
const dateColumns = new Set(
|
|
1266
|
+
Object.keys(storage.TABLE_SCHEMAS[tableName]).filter((key) => storage.TABLE_SCHEMAS[tableName][key].type === "timestamp").map((key) => key)
|
|
1267
|
+
);
|
|
1268
|
+
for (const [key, value] of Object.entries(sqlRow)) {
|
|
1269
|
+
if (value === null || value === void 0) {
|
|
1270
|
+
result[key] = value;
|
|
1271
|
+
continue;
|
|
1098
1272
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1273
|
+
if (dateColumns.has(key) && typeof value === "string") {
|
|
1274
|
+
result[key] = new Date(value);
|
|
1275
|
+
continue;
|
|
1276
|
+
}
|
|
1277
|
+
if (jsonColumns.has(key) && typeof value === "string") {
|
|
1278
|
+
result[key] = storage.safelyParseJSON(value);
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
result[key] = value;
|
|
1282
|
+
}
|
|
1283
|
+
return result;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
// src/storage/db/index.ts
|
|
1287
|
+
function resolveClient(config) {
|
|
1288
|
+
if ("client" in config) {
|
|
1289
|
+
return config.client;
|
|
1290
|
+
}
|
|
1291
|
+
return client.createClient({
|
|
1292
|
+
url: config.url,
|
|
1293
|
+
...config.authToken ? { authToken: config.authToken } : {}
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
var LibSQLDB = class extends base.MastraBase {
|
|
1297
|
+
client;
|
|
1298
|
+
maxRetries;
|
|
1299
|
+
initialBackoffMs;
|
|
1300
|
+
executeWriteOperationWithRetry;
|
|
1301
|
+
constructor({
|
|
1302
|
+
client,
|
|
1303
|
+
maxRetries,
|
|
1304
|
+
initialBackoffMs
|
|
1305
|
+
}) {
|
|
1306
|
+
super({
|
|
1307
|
+
component: "STORAGE",
|
|
1308
|
+
name: "LIBSQL_DB_LAYER"
|
|
1309
|
+
});
|
|
1310
|
+
this.client = client;
|
|
1311
|
+
this.maxRetries = maxRetries ?? 5;
|
|
1312
|
+
this.initialBackoffMs = initialBackoffMs ?? 100;
|
|
1313
|
+
this.executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
1314
|
+
logger: this.logger,
|
|
1315
|
+
maxRetries: this.maxRetries,
|
|
1316
|
+
initialBackoffMs: this.initialBackoffMs
|
|
1107
1317
|
});
|
|
1108
|
-
return dedupedRows;
|
|
1109
1318
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1319
|
+
/**
|
|
1320
|
+
* Checks if a column exists in the specified table.
|
|
1321
|
+
*
|
|
1322
|
+
* @param table - The name of the table to check
|
|
1323
|
+
* @param column - The name of the column to look for
|
|
1324
|
+
* @returns `true` if the column exists in the table, `false` otherwise
|
|
1325
|
+
*/
|
|
1326
|
+
async hasColumn(table, column) {
|
|
1327
|
+
const sanitizedTable = utils.parseSqlIdentifier(table, "table name");
|
|
1328
|
+
const result = await this.client.execute({
|
|
1329
|
+
sql: `PRAGMA table_info("${sanitizedTable}")`
|
|
1330
|
+
});
|
|
1331
|
+
return result.rows?.some((row) => row.name === column);
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Internal insert implementation without retry logic.
|
|
1335
|
+
*/
|
|
1336
|
+
async doInsert({
|
|
1337
|
+
tableName,
|
|
1338
|
+
record
|
|
1115
1339
|
}) {
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1340
|
+
await this.client.execute(
|
|
1341
|
+
prepareStatement({
|
|
1342
|
+
tableName,
|
|
1343
|
+
record
|
|
1344
|
+
})
|
|
1345
|
+
);
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Inserts or replaces a record in the specified table with automatic retry on lock errors.
|
|
1349
|
+
*
|
|
1350
|
+
* @param args - The insert arguments
|
|
1351
|
+
* @param args.tableName - The name of the table to insert into
|
|
1352
|
+
* @param args.record - The record to insert (key-value pairs)
|
|
1353
|
+
*/
|
|
1354
|
+
insert(args) {
|
|
1355
|
+
return this.executeWriteOperationWithRetry(() => this.doInsert(args), `insert into table ${args.tableName}`);
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Internal update implementation without retry logic.
|
|
1359
|
+
*/
|
|
1360
|
+
async doUpdate({
|
|
1361
|
+
tableName,
|
|
1362
|
+
keys,
|
|
1363
|
+
data
|
|
1364
|
+
}) {
|
|
1365
|
+
await this.client.execute(prepareUpdateStatement({ tableName, updates: data, keys }));
|
|
1366
|
+
}
|
|
1367
|
+
/**
|
|
1368
|
+
* Updates a record in the specified table with automatic retry on lock errors.
|
|
1369
|
+
*
|
|
1370
|
+
* @param args - The update arguments
|
|
1371
|
+
* @param args.tableName - The name of the table to update
|
|
1372
|
+
* @param args.keys - The key(s) identifying the record to update
|
|
1373
|
+
* @param args.data - The fields to update (key-value pairs)
|
|
1374
|
+
*/
|
|
1375
|
+
update(args) {
|
|
1376
|
+
return this.executeWriteOperationWithRetry(() => this.doUpdate(args), `update table ${args.tableName}`);
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* Internal batch insert implementation without retry logic.
|
|
1380
|
+
*/
|
|
1381
|
+
async doBatchInsert({
|
|
1382
|
+
tableName,
|
|
1383
|
+
records
|
|
1384
|
+
}) {
|
|
1385
|
+
if (records.length === 0) return;
|
|
1386
|
+
const batchStatements = records.map((r) => prepareStatement({ tableName, record: r }));
|
|
1387
|
+
await this.client.batch(batchStatements, "write");
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* Inserts multiple records in a single batch transaction with automatic retry on lock errors.
|
|
1391
|
+
*
|
|
1392
|
+
* @param args - The batch insert arguments
|
|
1393
|
+
* @param args.tableName - The name of the table to insert into
|
|
1394
|
+
* @param args.records - Array of records to insert
|
|
1395
|
+
* @throws {MastraError} When the batch insert fails after retries
|
|
1396
|
+
*/
|
|
1397
|
+
async batchInsert(args) {
|
|
1398
|
+
return this.executeWriteOperationWithRetry(
|
|
1399
|
+
() => this.doBatchInsert(args),
|
|
1400
|
+
`batch insert into table ${args.tableName}`
|
|
1401
|
+
).catch((error$1) => {
|
|
1152
1402
|
throw new error.MastraError(
|
|
1153
1403
|
{
|
|
1154
|
-
id: "
|
|
1404
|
+
id: storage.createStorageErrorId("LIBSQL", "BATCH_INSERT", "FAILED"),
|
|
1155
1405
|
domain: error.ErrorDomain.STORAGE,
|
|
1156
1406
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1157
|
-
details: {
|
|
1407
|
+
details: {
|
|
1408
|
+
tableName: args.tableName
|
|
1409
|
+
}
|
|
1158
1410
|
},
|
|
1159
1411
|
error$1
|
|
1160
1412
|
);
|
|
1161
|
-
}
|
|
1413
|
+
});
|
|
1162
1414
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1415
|
+
/**
|
|
1416
|
+
* Internal batch update implementation without retry logic.
|
|
1417
|
+
* Each record can be updated based on single or composite keys.
|
|
1418
|
+
*/
|
|
1419
|
+
async doBatchUpdate({
|
|
1420
|
+
tableName,
|
|
1421
|
+
updates
|
|
1166
1422
|
}) {
|
|
1167
|
-
if (
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1423
|
+
if (updates.length === 0) return;
|
|
1424
|
+
const batchStatements = updates.map(
|
|
1425
|
+
({ keys, data }) => prepareUpdateStatement({
|
|
1426
|
+
tableName,
|
|
1427
|
+
updates: data,
|
|
1428
|
+
keys
|
|
1429
|
+
})
|
|
1430
|
+
);
|
|
1431
|
+
await this.client.batch(batchStatements, "write");
|
|
1432
|
+
}
|
|
1433
|
+
/**
|
|
1434
|
+
* Updates multiple records in a single batch transaction with automatic retry on lock errors.
|
|
1435
|
+
* Each record can be updated based on single or composite keys.
|
|
1436
|
+
*
|
|
1437
|
+
* @param args - The batch update arguments
|
|
1438
|
+
* @param args.tableName - The name of the table to update
|
|
1439
|
+
* @param args.updates - Array of update operations, each containing keys and data
|
|
1440
|
+
* @throws {MastraError} When the batch update fails after retries
|
|
1441
|
+
*/
|
|
1442
|
+
async batchUpdate(args) {
|
|
1443
|
+
return this.executeWriteOperationWithRetry(
|
|
1444
|
+
() => this.doBatchUpdate(args),
|
|
1445
|
+
`batch update in table ${args.tableName}`
|
|
1446
|
+
).catch((error$1) => {
|
|
1188
1447
|
throw new error.MastraError(
|
|
1189
1448
|
{
|
|
1190
|
-
id: "
|
|
1449
|
+
id: storage.createStorageErrorId("LIBSQL", "BATCH_UPDATE", "FAILED"),
|
|
1191
1450
|
domain: error.ErrorDomain.STORAGE,
|
|
1192
1451
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1193
|
-
details: {
|
|
1452
|
+
details: {
|
|
1453
|
+
tableName: args.tableName
|
|
1454
|
+
}
|
|
1194
1455
|
},
|
|
1195
1456
|
error$1
|
|
1196
1457
|
);
|
|
1197
|
-
}
|
|
1458
|
+
});
|
|
1198
1459
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1460
|
+
/**
|
|
1461
|
+
* Internal batch delete implementation without retry logic.
|
|
1462
|
+
* Each record can be deleted based on single or composite keys.
|
|
1463
|
+
*/
|
|
1464
|
+
async doBatchDelete({
|
|
1465
|
+
tableName,
|
|
1466
|
+
keys
|
|
1467
|
+
}) {
|
|
1468
|
+
if (keys.length === 0) return;
|
|
1469
|
+
const batchStatements = keys.map(
|
|
1470
|
+
(keyObj) => prepareDeleteStatement({
|
|
1471
|
+
tableName,
|
|
1472
|
+
keys: keyObj
|
|
1473
|
+
})
|
|
1474
|
+
);
|
|
1475
|
+
await this.client.batch(batchStatements, "write");
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Deletes multiple records in a single batch transaction with automatic retry on lock errors.
|
|
1479
|
+
* Each record can be deleted based on single or composite keys.
|
|
1480
|
+
*
|
|
1481
|
+
* @param args - The batch delete arguments
|
|
1482
|
+
* @param args.tableName - The name of the table to delete from
|
|
1483
|
+
* @param args.keys - Array of key objects identifying records to delete
|
|
1484
|
+
* @throws {MastraError} When the batch delete fails after retries
|
|
1485
|
+
*/
|
|
1486
|
+
async batchDelete({
|
|
1487
|
+
tableName,
|
|
1488
|
+
keys
|
|
1489
|
+
}) {
|
|
1490
|
+
return this.executeWriteOperationWithRetry(
|
|
1491
|
+
() => this.doBatchDelete({ tableName, keys }),
|
|
1492
|
+
`batch delete from table ${tableName}`
|
|
1493
|
+
).catch((error$1) => {
|
|
1494
|
+
throw new error.MastraError(
|
|
1495
|
+
{
|
|
1496
|
+
id: storage.createStorageErrorId("LIBSQL", "BATCH_DELETE", "FAILED"),
|
|
1497
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1498
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1499
|
+
details: {
|
|
1500
|
+
tableName
|
|
1501
|
+
}
|
|
1502
|
+
},
|
|
1503
|
+
error$1
|
|
1504
|
+
);
|
|
1505
|
+
});
|
|
1506
|
+
}
|
|
1507
|
+
/**
|
|
1508
|
+
* Internal single-record delete implementation without retry logic.
|
|
1509
|
+
*/
|
|
1510
|
+
async doDelete({ tableName, keys }) {
|
|
1511
|
+
await this.client.execute(prepareDeleteStatement({ tableName, keys }));
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Deletes a single record from the specified table with automatic retry on lock errors.
|
|
1515
|
+
*
|
|
1516
|
+
* @param args - The delete arguments
|
|
1517
|
+
* @param args.tableName - The name of the table to delete from
|
|
1518
|
+
* @param args.keys - The key(s) identifying the record to delete
|
|
1519
|
+
* @throws {MastraError} When the delete fails after retries
|
|
1520
|
+
*/
|
|
1521
|
+
async delete(args) {
|
|
1522
|
+
return this.executeWriteOperationWithRetry(() => this.doDelete(args), `delete from table ${args.tableName}`).catch(
|
|
1523
|
+
(error$1) => {
|
|
1524
|
+
throw new error.MastraError(
|
|
1525
|
+
{
|
|
1526
|
+
id: storage.createStorageErrorId("LIBSQL", "DELETE", "FAILED"),
|
|
1527
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1528
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1529
|
+
details: {
|
|
1530
|
+
tableName: args.tableName
|
|
1531
|
+
}
|
|
1532
|
+
},
|
|
1533
|
+
error$1
|
|
1534
|
+
);
|
|
1236
1535
|
}
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1536
|
+
);
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Selects a single record from the specified table by key(s).
|
|
1540
|
+
* Returns the most recently created record if multiple matches exist.
|
|
1541
|
+
* Automatically parses JSON string values back to objects/arrays.
|
|
1542
|
+
*
|
|
1543
|
+
* @typeParam R - The expected return type of the record
|
|
1544
|
+
* @param args - The select arguments
|
|
1545
|
+
* @param args.tableName - The name of the table to select from
|
|
1546
|
+
* @param args.keys - The key(s) identifying the record to select
|
|
1547
|
+
* @returns The matching record or `null` if not found
|
|
1548
|
+
*/
|
|
1549
|
+
async select({ tableName, keys }) {
|
|
1550
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1551
|
+
const parsedKeys = Object.keys(keys).map((key) => utils.parseSqlIdentifier(key, "column name"));
|
|
1552
|
+
const conditions = parsedKeys.map((key) => `${key} = ?`).join(" AND ");
|
|
1553
|
+
const values = Object.values(keys);
|
|
1554
|
+
const result = await this.client.execute({
|
|
1555
|
+
sql: `SELECT * FROM ${parsedTableName} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
1556
|
+
args: values
|
|
1557
|
+
});
|
|
1558
|
+
if (!result.rows || result.rows.length === 0) {
|
|
1559
|
+
return null;
|
|
1560
|
+
}
|
|
1561
|
+
const row = result.rows[0];
|
|
1562
|
+
const parsed = Object.fromEntries(
|
|
1563
|
+
Object.entries(row || {}).map(([k, v]) => {
|
|
1564
|
+
try {
|
|
1565
|
+
return [k, typeof v === "string" ? v.startsWith("{") || v.startsWith("[") ? JSON.parse(v) : v : v];
|
|
1566
|
+
} catch {
|
|
1567
|
+
return [k, v];
|
|
1568
|
+
}
|
|
1569
|
+
})
|
|
1570
|
+
);
|
|
1571
|
+
return parsed;
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Selects multiple records from the specified table with optional filtering, ordering, and pagination.
|
|
1575
|
+
*
|
|
1576
|
+
* @typeParam R - The expected return type of each record
|
|
1577
|
+
* @param args - The select arguments
|
|
1578
|
+
* @param args.tableName - The name of the table to select from
|
|
1579
|
+
* @param args.whereClause - Optional WHERE clause with SQL string and arguments
|
|
1580
|
+
* @param args.orderBy - Optional ORDER BY clause (e.g., "createdAt DESC")
|
|
1581
|
+
* @param args.offset - Optional offset for pagination
|
|
1582
|
+
* @param args.limit - Optional limit for pagination
|
|
1583
|
+
* @param args.args - Optional additional query arguments
|
|
1584
|
+
* @returns Array of matching records
|
|
1585
|
+
*/
|
|
1586
|
+
async selectMany({
|
|
1587
|
+
tableName,
|
|
1588
|
+
whereClause,
|
|
1589
|
+
orderBy,
|
|
1590
|
+
offset,
|
|
1591
|
+
limit,
|
|
1592
|
+
args
|
|
1593
|
+
}) {
|
|
1594
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1595
|
+
let statement = `SELECT * FROM ${parsedTableName}`;
|
|
1596
|
+
if (whereClause?.sql) {
|
|
1597
|
+
statement += `${whereClause.sql}`;
|
|
1598
|
+
}
|
|
1599
|
+
if (orderBy) {
|
|
1600
|
+
statement += ` ORDER BY ${orderBy}`;
|
|
1601
|
+
}
|
|
1602
|
+
if (limit) {
|
|
1603
|
+
statement += ` LIMIT ${limit}`;
|
|
1604
|
+
}
|
|
1605
|
+
if (offset) {
|
|
1606
|
+
statement += ` OFFSET ${offset}`;
|
|
1607
|
+
}
|
|
1608
|
+
const result = await this.client.execute({
|
|
1609
|
+
sql: statement,
|
|
1610
|
+
args: [...whereClause?.args ?? [], ...args ?? []]
|
|
1611
|
+
});
|
|
1612
|
+
return result.rows;
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Returns the total count of records matching the optional WHERE clause.
|
|
1616
|
+
*
|
|
1617
|
+
* @param args - The count arguments
|
|
1618
|
+
* @param args.tableName - The name of the table to count from
|
|
1619
|
+
* @param args.whereClause - Optional WHERE clause with SQL string and arguments
|
|
1620
|
+
* @returns The total count of matching records
|
|
1621
|
+
*/
|
|
1622
|
+
async selectTotalCount({
|
|
1623
|
+
tableName,
|
|
1624
|
+
whereClause
|
|
1625
|
+
}) {
|
|
1626
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1627
|
+
const statement = `SELECT COUNT(*) as count FROM ${parsedTableName} ${whereClause ? `${whereClause.sql}` : ""}`;
|
|
1628
|
+
const result = await this.client.execute({
|
|
1629
|
+
sql: statement,
|
|
1630
|
+
args: whereClause?.args ?? []
|
|
1631
|
+
});
|
|
1632
|
+
if (!result.rows || result.rows.length === 0) {
|
|
1633
|
+
return 0;
|
|
1634
|
+
}
|
|
1635
|
+
return result.rows[0]?.count ?? 0;
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Maps a storage column type to its SQLite equivalent.
|
|
1639
|
+
*/
|
|
1640
|
+
getSqlType(type) {
|
|
1641
|
+
switch (type) {
|
|
1642
|
+
case "bigint":
|
|
1643
|
+
return "INTEGER";
|
|
1644
|
+
// SQLite uses INTEGER for all integer sizes
|
|
1645
|
+
case "timestamp":
|
|
1646
|
+
return "TEXT";
|
|
1647
|
+
// Store timestamps as ISO strings in SQLite
|
|
1648
|
+
case "float":
|
|
1649
|
+
return "REAL";
|
|
1650
|
+
// SQLite's floating point type
|
|
1651
|
+
case "boolean":
|
|
1652
|
+
return "INTEGER";
|
|
1653
|
+
// SQLite uses 0/1 for booleans
|
|
1654
|
+
case "jsonb":
|
|
1655
|
+
return "TEXT";
|
|
1656
|
+
// Store JSON as TEXT in SQLite
|
|
1657
|
+
default:
|
|
1658
|
+
return storage.getSqlType(type);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
/**
|
|
1662
|
+
* Creates a table if it doesn't exist based on the provided schema.
|
|
1663
|
+
*
|
|
1664
|
+
* @param args - The create table arguments
|
|
1665
|
+
* @param args.tableName - The name of the table to create
|
|
1666
|
+
* @param args.schema - The schema definition for the table columns
|
|
1667
|
+
*/
|
|
1668
|
+
async createTable({
|
|
1669
|
+
tableName,
|
|
1670
|
+
schema
|
|
1671
|
+
}) {
|
|
1672
|
+
try {
|
|
1673
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1674
|
+
const columnDefinitions = Object.entries(schema).map(([colName, colDef]) => {
|
|
1675
|
+
const type = this.getSqlType(colDef.type);
|
|
1676
|
+
const nullable = colDef.nullable === false ? "NOT NULL" : "";
|
|
1677
|
+
const primaryKey = colDef.primaryKey ? "PRIMARY KEY" : "";
|
|
1678
|
+
return `"${colName}" ${type} ${nullable} ${primaryKey}`.trim();
|
|
1241
1679
|
});
|
|
1242
|
-
const
|
|
1243
|
-
if (
|
|
1244
|
-
|
|
1245
|
-
messages: [],
|
|
1246
|
-
total: 0,
|
|
1247
|
-
page,
|
|
1248
|
-
perPage,
|
|
1249
|
-
hasMore: false
|
|
1250
|
-
};
|
|
1680
|
+
const tableConstraints = [];
|
|
1681
|
+
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
1682
|
+
tableConstraints.push("UNIQUE (workflow_name, run_id)");
|
|
1251
1683
|
}
|
|
1252
|
-
const
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
});
|
|
1258
|
-
messages.push(...(dataResult.rows || []).map((row) => this.parseRow(row)));
|
|
1259
|
-
const messagesToReturn = format === "v1" ? new agent.MessageList().add(messages, "memory").get.all.v1() : new agent.MessageList().add(messages, "memory").get.all.v2();
|
|
1260
|
-
return {
|
|
1261
|
-
messages: messagesToReturn,
|
|
1262
|
-
total,
|
|
1263
|
-
page,
|
|
1264
|
-
perPage,
|
|
1265
|
-
hasMore: currentOffset + messages.length < total
|
|
1266
|
-
};
|
|
1684
|
+
const allDefinitions = [...columnDefinitions, ...tableConstraints].join(",\n ");
|
|
1685
|
+
const sql = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
1686
|
+
${allDefinitions}
|
|
1687
|
+
)`;
|
|
1688
|
+
await this.client.execute(sql);
|
|
1689
|
+
this.logger.debug(`LibSQLDB: Created table ${tableName}`);
|
|
1267
1690
|
} catch (error$1) {
|
|
1268
|
-
|
|
1691
|
+
throw new error.MastraError(
|
|
1269
1692
|
{
|
|
1270
|
-
id: "
|
|
1693
|
+
id: storage.createStorageErrorId("LIBSQL", "CREATE_TABLE", "FAILED"),
|
|
1271
1694
|
domain: error.ErrorDomain.STORAGE,
|
|
1272
1695
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1273
|
-
details: {
|
|
1696
|
+
details: { tableName }
|
|
1274
1697
|
},
|
|
1275
1698
|
error$1
|
|
1276
1699
|
);
|
|
1277
|
-
this.logger?.trackException?.(mastraError);
|
|
1278
|
-
this.logger?.error?.(mastraError.toString());
|
|
1279
|
-
return { messages: [], total: 0, page, perPage, hasMore: false };
|
|
1280
1700
|
}
|
|
1281
1701
|
}
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1702
|
+
/**
|
|
1703
|
+
* Gets a default value for a column type (used when adding NOT NULL columns).
|
|
1704
|
+
*/
|
|
1705
|
+
getDefaultValue(type) {
|
|
1706
|
+
switch (type) {
|
|
1707
|
+
case "text":
|
|
1708
|
+
case "uuid":
|
|
1709
|
+
return "DEFAULT ''";
|
|
1710
|
+
case "integer":
|
|
1711
|
+
case "bigint":
|
|
1712
|
+
case "float":
|
|
1713
|
+
return "DEFAULT 0";
|
|
1714
|
+
case "boolean":
|
|
1715
|
+
return "DEFAULT 0";
|
|
1716
|
+
case "jsonb":
|
|
1717
|
+
return "DEFAULT '{}'";
|
|
1718
|
+
case "timestamp":
|
|
1719
|
+
return "DEFAULT CURRENT_TIMESTAMP";
|
|
1720
|
+
default:
|
|
1721
|
+
return "DEFAULT ''";
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
/**
|
|
1725
|
+
* Alters an existing table to add missing columns.
|
|
1726
|
+
* Used for schema migrations when new columns are added.
|
|
1727
|
+
*
|
|
1728
|
+
* @param args - The alter table arguments
|
|
1729
|
+
* @param args.tableName - The name of the table to alter
|
|
1730
|
+
* @param args.schema - The full schema definition for the table
|
|
1731
|
+
* @param args.ifNotExists - Array of column names to add if they don't exist
|
|
1732
|
+
*/
|
|
1733
|
+
async alterTable({
|
|
1734
|
+
tableName,
|
|
1735
|
+
schema,
|
|
1736
|
+
ifNotExists
|
|
1285
1737
|
}) {
|
|
1286
|
-
|
|
1738
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1287
1739
|
try {
|
|
1288
|
-
const
|
|
1289
|
-
|
|
1290
|
-
throw new Error("Thread ID is required");
|
|
1291
|
-
}
|
|
1292
|
-
const batchStatements = messages.map((message) => {
|
|
1293
|
-
const time = message.createdAt || /* @__PURE__ */ new Date();
|
|
1294
|
-
if (!message.threadId) {
|
|
1295
|
-
throw new Error(
|
|
1296
|
-
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1297
|
-
);
|
|
1298
|
-
}
|
|
1299
|
-
if (!message.resourceId) {
|
|
1300
|
-
throw new Error(
|
|
1301
|
-
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1302
|
-
);
|
|
1303
|
-
}
|
|
1304
|
-
return {
|
|
1305
|
-
sql: `INSERT INTO "${storage.TABLE_MESSAGES}" (id, thread_id, content, role, type, "createdAt", "resourceId")
|
|
1306
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
1307
|
-
ON CONFLICT(id) DO UPDATE SET
|
|
1308
|
-
thread_id=excluded.thread_id,
|
|
1309
|
-
content=excluded.content,
|
|
1310
|
-
role=excluded.role,
|
|
1311
|
-
type=excluded.type,
|
|
1312
|
-
"resourceId"=excluded."resourceId"
|
|
1313
|
-
`,
|
|
1314
|
-
args: [
|
|
1315
|
-
message.id,
|
|
1316
|
-
message.threadId,
|
|
1317
|
-
typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
|
|
1318
|
-
message.role,
|
|
1319
|
-
message.type || "v2",
|
|
1320
|
-
time instanceof Date ? time.toISOString() : time,
|
|
1321
|
-
message.resourceId
|
|
1322
|
-
]
|
|
1323
|
-
};
|
|
1324
|
-
});
|
|
1325
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1326
|
-
batchStatements.push({
|
|
1327
|
-
sql: `UPDATE "${storage.TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
|
|
1328
|
-
args: [now, threadId]
|
|
1740
|
+
const tableInfo = await this.client.execute({
|
|
1741
|
+
sql: `PRAGMA table_info("${parsedTableName}")`
|
|
1329
1742
|
});
|
|
1330
|
-
const
|
|
1331
|
-
const
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1743
|
+
const existingColumns = new Set((tableInfo.rows || []).map((row) => row.name?.toLowerCase()));
|
|
1744
|
+
for (const columnName of ifNotExists) {
|
|
1745
|
+
if (!existingColumns.has(columnName.toLowerCase()) && schema[columnName]) {
|
|
1746
|
+
const columnDef = schema[columnName];
|
|
1747
|
+
const sqlType = this.getSqlType(columnDef.type);
|
|
1748
|
+
const defaultValue = this.getDefaultValue(columnDef.type);
|
|
1749
|
+
const alterSql = `ALTER TABLE ${parsedTableName} ADD COLUMN "${columnName}" ${sqlType} ${defaultValue}`;
|
|
1750
|
+
await this.client.execute(alterSql);
|
|
1751
|
+
this.logger.debug(`LibSQLDB: Added column ${columnName} to table ${tableName}`);
|
|
1337
1752
|
}
|
|
1338
1753
|
}
|
|
1339
|
-
if (threadUpdateStatement) {
|
|
1340
|
-
await this.client.execute(threadUpdateStatement);
|
|
1341
|
-
}
|
|
1342
|
-
const list = new agent.MessageList().add(messages, "memory");
|
|
1343
|
-
if (format === `v2`) return list.get.all.v2();
|
|
1344
|
-
return list.get.all.v1();
|
|
1345
1754
|
} catch (error$1) {
|
|
1346
1755
|
throw new error.MastraError(
|
|
1347
1756
|
{
|
|
1348
|
-
id: "
|
|
1757
|
+
id: storage.createStorageErrorId("LIBSQL", "ALTER_TABLE", "FAILED"),
|
|
1349
1758
|
domain: error.ErrorDomain.STORAGE,
|
|
1350
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1759
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1760
|
+
details: { tableName }
|
|
1351
1761
|
},
|
|
1352
1762
|
error$1
|
|
1353
1763
|
);
|
|
1354
1764
|
}
|
|
1355
1765
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
const
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
for (const existingMessage of existingMessages) {
|
|
1376
|
-
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
1377
|
-
if (!updatePayload) continue;
|
|
1378
|
-
const { id, ...fieldsToUpdate } = updatePayload;
|
|
1379
|
-
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
1380
|
-
threadIdsToUpdate.add(existingMessage.threadId);
|
|
1381
|
-
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
1382
|
-
threadIdsToUpdate.add(updatePayload.threadId);
|
|
1383
|
-
}
|
|
1384
|
-
const setClauses = [];
|
|
1385
|
-
const args = [];
|
|
1386
|
-
const updatableFields = { ...fieldsToUpdate };
|
|
1387
|
-
if (updatableFields.content) {
|
|
1388
|
-
const newContent = {
|
|
1389
|
-
...existingMessage.content,
|
|
1390
|
-
...updatableFields.content,
|
|
1391
|
-
// Deep merge metadata if it exists on both
|
|
1392
|
-
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
1393
|
-
metadata: {
|
|
1394
|
-
...existingMessage.content.metadata,
|
|
1395
|
-
...updatableFields.content.metadata
|
|
1396
|
-
}
|
|
1397
|
-
} : {}
|
|
1398
|
-
};
|
|
1399
|
-
setClauses.push(`${utils.parseSqlIdentifier("content", "column name")} = ?`);
|
|
1400
|
-
args.push(JSON.stringify(newContent));
|
|
1401
|
-
delete updatableFields.content;
|
|
1402
|
-
}
|
|
1403
|
-
for (const key in updatableFields) {
|
|
1404
|
-
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
1405
|
-
const dbKey = columnMapping[key] || key;
|
|
1406
|
-
setClauses.push(`${utils.parseSqlIdentifier(dbKey, "column name")} = ?`);
|
|
1407
|
-
let value = updatableFields[key];
|
|
1408
|
-
if (typeof value === "object" && value !== null) {
|
|
1409
|
-
value = JSON.stringify(value);
|
|
1766
|
+
/**
|
|
1767
|
+
* Deletes all records from the specified table.
|
|
1768
|
+
* Errors are logged but not thrown.
|
|
1769
|
+
*
|
|
1770
|
+
* @param args - The delete arguments
|
|
1771
|
+
* @param args.tableName - The name of the table to clear
|
|
1772
|
+
*/
|
|
1773
|
+
async deleteData({ tableName }) {
|
|
1774
|
+
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1775
|
+
try {
|
|
1776
|
+
await this.client.execute(`DELETE FROM ${parsedTableName}`);
|
|
1777
|
+
} catch (e) {
|
|
1778
|
+
const mastraError = new error.MastraError(
|
|
1779
|
+
{
|
|
1780
|
+
id: storage.createStorageErrorId("LIBSQL", "CLEAR_TABLE", "FAILED"),
|
|
1781
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1782
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1783
|
+
details: {
|
|
1784
|
+
tableName
|
|
1410
1785
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
const sql = `UPDATE ${storage.TABLE_MESSAGES} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
1417
|
-
batchStatements.push({ sql, args });
|
|
1418
|
-
}
|
|
1419
|
-
if (batchStatements.length === 0) {
|
|
1420
|
-
return existingMessages;
|
|
1421
|
-
}
|
|
1422
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1423
|
-
for (const threadId of threadIdsToUpdate) {
|
|
1424
|
-
if (threadId) {
|
|
1425
|
-
batchStatements.push({
|
|
1426
|
-
sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
1427
|
-
args: [now, threadId]
|
|
1428
|
-
});
|
|
1429
|
-
}
|
|
1786
|
+
},
|
|
1787
|
+
e
|
|
1788
|
+
);
|
|
1789
|
+
this.logger?.trackException?.(mastraError);
|
|
1790
|
+
this.logger?.error?.(mastraError.toString());
|
|
1430
1791
|
}
|
|
1431
|
-
await this.client.batch(batchStatements, "write");
|
|
1432
|
-
const updatedResult = await this.client.execute({ sql: selectSql, args: messageIds });
|
|
1433
|
-
return updatedResult.rows.map((row) => this.parseRow(row));
|
|
1434
1792
|
}
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1793
|
+
};
|
|
1794
|
+
|
|
1795
|
+
// src/storage/domains/agents/index.ts
|
|
1796
|
+
var AgentsLibSQL = class extends storage.AgentsStorage {
|
|
1797
|
+
#db;
|
|
1798
|
+
constructor(config) {
|
|
1799
|
+
super();
|
|
1800
|
+
const client = resolveClient(config);
|
|
1801
|
+
this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
|
|
1802
|
+
}
|
|
1803
|
+
async init() {
|
|
1804
|
+
await this.#db.createTable({ tableName: storage.TABLE_AGENTS, schema: storage.AGENTS_SCHEMA });
|
|
1805
|
+
}
|
|
1806
|
+
async dangerouslyClearAll() {
|
|
1807
|
+
await this.#db.deleteData({ tableName: storage.TABLE_AGENTS });
|
|
1808
|
+
}
|
|
1809
|
+
parseJson(value, fieldName) {
|
|
1810
|
+
if (!value) return void 0;
|
|
1811
|
+
if (typeof value !== "string") return value;
|
|
1439
1812
|
try {
|
|
1440
|
-
|
|
1441
|
-
const threadIds = /* @__PURE__ */ new Set();
|
|
1442
|
-
const tx = await this.client.transaction("write");
|
|
1443
|
-
try {
|
|
1444
|
-
for (let i = 0; i < messageIds.length; i += BATCH_SIZE) {
|
|
1445
|
-
const batch = messageIds.slice(i, i + BATCH_SIZE);
|
|
1446
|
-
const placeholders = batch.map(() => "?").join(",");
|
|
1447
|
-
const result = await tx.execute({
|
|
1448
|
-
sql: `SELECT DISTINCT thread_id FROM "${storage.TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
|
|
1449
|
-
args: batch
|
|
1450
|
-
});
|
|
1451
|
-
result.rows?.forEach((row) => {
|
|
1452
|
-
if (row.thread_id) threadIds.add(row.thread_id);
|
|
1453
|
-
});
|
|
1454
|
-
await tx.execute({
|
|
1455
|
-
sql: `DELETE FROM "${storage.TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
|
|
1456
|
-
args: batch
|
|
1457
|
-
});
|
|
1458
|
-
}
|
|
1459
|
-
if (threadIds.size > 0) {
|
|
1460
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1461
|
-
for (const threadId of threadIds) {
|
|
1462
|
-
await tx.execute({
|
|
1463
|
-
sql: `UPDATE "${storage.TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
|
|
1464
|
-
args: [now, threadId]
|
|
1465
|
-
});
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
await tx.commit();
|
|
1469
|
-
} catch (error) {
|
|
1470
|
-
await tx.rollback();
|
|
1471
|
-
throw error;
|
|
1472
|
-
}
|
|
1813
|
+
return JSON.parse(value);
|
|
1473
1814
|
} catch (error$1) {
|
|
1815
|
+
const details = {
|
|
1816
|
+
value: value.length > 100 ? value.substring(0, 100) + "..." : value
|
|
1817
|
+
};
|
|
1818
|
+
if (fieldName) {
|
|
1819
|
+
details.field = fieldName;
|
|
1820
|
+
}
|
|
1474
1821
|
throw new error.MastraError(
|
|
1475
1822
|
{
|
|
1476
|
-
id: "
|
|
1823
|
+
id: storage.createStorageErrorId("LIBSQL", "PARSE_JSON", "INVALID_JSON"),
|
|
1477
1824
|
domain: error.ErrorDomain.STORAGE,
|
|
1478
|
-
category: error.ErrorCategory.
|
|
1479
|
-
|
|
1825
|
+
category: error.ErrorCategory.SYSTEM,
|
|
1826
|
+
text: `Failed to parse JSON${fieldName ? ` for field "${fieldName}"` : ""}: ${error$1 instanceof Error ? error$1.message : "Unknown error"}`,
|
|
1827
|
+
details
|
|
1480
1828
|
},
|
|
1481
1829
|
error$1
|
|
1482
1830
|
);
|
|
1483
1831
|
}
|
|
1484
1832
|
}
|
|
1485
|
-
|
|
1486
|
-
const result = await this.operations.load({
|
|
1487
|
-
tableName: storage.TABLE_RESOURCES,
|
|
1488
|
-
keys: { id: resourceId }
|
|
1489
|
-
});
|
|
1490
|
-
if (!result) {
|
|
1491
|
-
return null;
|
|
1492
|
-
}
|
|
1833
|
+
parseRow(row) {
|
|
1493
1834
|
return {
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1835
|
+
id: row.id,
|
|
1836
|
+
name: row.name,
|
|
1837
|
+
description: row.description,
|
|
1838
|
+
instructions: row.instructions,
|
|
1839
|
+
model: this.parseJson(row.model, "model"),
|
|
1840
|
+
tools: this.parseJson(row.tools, "tools"),
|
|
1841
|
+
defaultOptions: this.parseJson(row.defaultOptions, "defaultOptions"),
|
|
1842
|
+
workflows: this.parseJson(row.workflows, "workflows"),
|
|
1843
|
+
agents: this.parseJson(row.agents, "agents"),
|
|
1844
|
+
inputProcessors: this.parseJson(row.inputProcessors, "inputProcessors"),
|
|
1845
|
+
outputProcessors: this.parseJson(row.outputProcessors, "outputProcessors"),
|
|
1846
|
+
memory: this.parseJson(row.memory, "memory"),
|
|
1847
|
+
scorers: this.parseJson(row.scorers, "scorers"),
|
|
1848
|
+
metadata: this.parseJson(row.metadata, "metadata"),
|
|
1849
|
+
createdAt: new Date(row.createdAt),
|
|
1850
|
+
updatedAt: new Date(row.updatedAt)
|
|
1500
1851
|
};
|
|
1501
1852
|
}
|
|
1502
|
-
async
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
})
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
const newResource = {
|
|
1520
|
-
id: resourceId,
|
|
1521
|
-
workingMemory,
|
|
1522
|
-
metadata: metadata || {},
|
|
1523
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
1524
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
1525
|
-
};
|
|
1526
|
-
return this.saveResource({ resource: newResource });
|
|
1527
|
-
}
|
|
1528
|
-
const updatedResource = {
|
|
1529
|
-
...existingResource,
|
|
1530
|
-
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
1531
|
-
metadata: {
|
|
1532
|
-
...existingResource.metadata,
|
|
1533
|
-
...metadata
|
|
1534
|
-
},
|
|
1535
|
-
updatedAt: /* @__PURE__ */ new Date()
|
|
1536
|
-
};
|
|
1537
|
-
const updates = [];
|
|
1538
|
-
const values = [];
|
|
1539
|
-
if (workingMemory !== void 0) {
|
|
1540
|
-
updates.push("workingMemory = ?");
|
|
1541
|
-
values.push(workingMemory);
|
|
1542
|
-
}
|
|
1543
|
-
if (metadata) {
|
|
1544
|
-
updates.push("metadata = ?");
|
|
1545
|
-
values.push(JSON.stringify(updatedResource.metadata));
|
|
1853
|
+
async getAgentById({ id }) {
|
|
1854
|
+
try {
|
|
1855
|
+
const result = await this.#db.select({
|
|
1856
|
+
tableName: storage.TABLE_AGENTS,
|
|
1857
|
+
keys: { id }
|
|
1858
|
+
});
|
|
1859
|
+
return result ? this.parseRow(result) : null;
|
|
1860
|
+
} catch (error$1) {
|
|
1861
|
+
throw new error.MastraError(
|
|
1862
|
+
{
|
|
1863
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_AGENT_BY_ID", "FAILED"),
|
|
1864
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1865
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1866
|
+
details: { agentId: id }
|
|
1867
|
+
},
|
|
1868
|
+
error$1
|
|
1869
|
+
);
|
|
1546
1870
|
}
|
|
1547
|
-
updates.push("updatedAt = ?");
|
|
1548
|
-
values.push(updatedResource.updatedAt.toISOString());
|
|
1549
|
-
values.push(resourceId);
|
|
1550
|
-
await this.client.execute({
|
|
1551
|
-
sql: `UPDATE ${storage.TABLE_RESOURCES} SET ${updates.join(", ")} WHERE id = ?`,
|
|
1552
|
-
args: values
|
|
1553
|
-
});
|
|
1554
|
-
return updatedResource;
|
|
1555
1871
|
}
|
|
1556
|
-
async
|
|
1872
|
+
async createAgent({ agent }) {
|
|
1557
1873
|
try {
|
|
1558
|
-
const
|
|
1559
|
-
|
|
1560
|
-
|
|
1874
|
+
const now = /* @__PURE__ */ new Date();
|
|
1875
|
+
await this.#db.insert({
|
|
1876
|
+
tableName: storage.TABLE_AGENTS,
|
|
1877
|
+
record: {
|
|
1878
|
+
id: agent.id,
|
|
1879
|
+
name: agent.name,
|
|
1880
|
+
description: agent.description ?? null,
|
|
1881
|
+
instructions: agent.instructions,
|
|
1882
|
+
model: agent.model,
|
|
1883
|
+
tools: agent.tools ?? null,
|
|
1884
|
+
defaultOptions: agent.defaultOptions ?? null,
|
|
1885
|
+
workflows: agent.workflows ?? null,
|
|
1886
|
+
agents: agent.agents ?? null,
|
|
1887
|
+
inputProcessors: agent.inputProcessors ?? null,
|
|
1888
|
+
outputProcessors: agent.outputProcessors ?? null,
|
|
1889
|
+
memory: agent.memory ?? null,
|
|
1890
|
+
scorers: agent.scorers ?? null,
|
|
1891
|
+
metadata: agent.metadata ?? null,
|
|
1892
|
+
createdAt: now,
|
|
1893
|
+
updatedAt: now
|
|
1894
|
+
}
|
|
1561
1895
|
});
|
|
1562
|
-
if (!result) {
|
|
1563
|
-
return null;
|
|
1564
|
-
}
|
|
1565
1896
|
return {
|
|
1566
|
-
...
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
updatedAt: new Date(result.updatedAt)
|
|
1897
|
+
...agent,
|
|
1898
|
+
createdAt: now,
|
|
1899
|
+
updatedAt: now
|
|
1570
1900
|
};
|
|
1571
1901
|
} catch (error$1) {
|
|
1572
1902
|
throw new error.MastraError(
|
|
1573
1903
|
{
|
|
1574
|
-
id: "
|
|
1904
|
+
id: storage.createStorageErrorId("LIBSQL", "CREATE_AGENT", "FAILED"),
|
|
1575
1905
|
domain: error.ErrorDomain.STORAGE,
|
|
1576
1906
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1577
|
-
details: {
|
|
1907
|
+
details: { agentId: agent.id }
|
|
1578
1908
|
},
|
|
1579
1909
|
error$1
|
|
1580
1910
|
);
|
|
1581
1911
|
}
|
|
1582
1912
|
}
|
|
1583
|
-
|
|
1584
|
-
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
1585
|
-
*/
|
|
1586
|
-
async getThreadsByResourceId(args) {
|
|
1587
|
-
const resourceId = args.resourceId;
|
|
1588
|
-
const orderBy = this.castThreadOrderBy(args.orderBy);
|
|
1589
|
-
const sortDirection = this.castThreadSortDirection(args.sortDirection);
|
|
1913
|
+
async updateAgent({ id, ...updates }) {
|
|
1590
1914
|
try {
|
|
1591
|
-
const
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
if (
|
|
1608
|
-
|
|
1915
|
+
const existingAgent = await this.getAgentById({ id });
|
|
1916
|
+
if (!existingAgent) {
|
|
1917
|
+
throw new error.MastraError({
|
|
1918
|
+
id: storage.createStorageErrorId("LIBSQL", "UPDATE_AGENT", "NOT_FOUND"),
|
|
1919
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1920
|
+
category: error.ErrorCategory.USER,
|
|
1921
|
+
text: `Agent ${id} not found`,
|
|
1922
|
+
details: { agentId: id }
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
const data = {
|
|
1926
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
1927
|
+
};
|
|
1928
|
+
if (updates.name !== void 0) data.name = updates.name;
|
|
1929
|
+
if (updates.description !== void 0) data.description = updates.description;
|
|
1930
|
+
if (updates.instructions !== void 0) data.instructions = updates.instructions;
|
|
1931
|
+
if (updates.model !== void 0) data.model = updates.model;
|
|
1932
|
+
if (updates.tools !== void 0) data.tools = updates.tools;
|
|
1933
|
+
if (updates.defaultOptions !== void 0) data.defaultOptions = updates.defaultOptions;
|
|
1934
|
+
if (updates.workflows !== void 0) data.workflows = updates.workflows;
|
|
1935
|
+
if (updates.agents !== void 0) data.agents = updates.agents;
|
|
1936
|
+
if (updates.inputProcessors !== void 0) data.inputProcessors = updates.inputProcessors;
|
|
1937
|
+
if (updates.outputProcessors !== void 0) data.outputProcessors = updates.outputProcessors;
|
|
1938
|
+
if (updates.memory !== void 0) data.memory = updates.memory;
|
|
1939
|
+
if (updates.scorers !== void 0) data.scorers = updates.scorers;
|
|
1940
|
+
if (updates.metadata !== void 0) {
|
|
1941
|
+
data.metadata = { ...existingAgent.metadata, ...updates.metadata };
|
|
1942
|
+
}
|
|
1943
|
+
if (Object.keys(data).length > 1) {
|
|
1944
|
+
await this.#db.update({
|
|
1945
|
+
tableName: storage.TABLE_AGENTS,
|
|
1946
|
+
keys: { id },
|
|
1947
|
+
data
|
|
1948
|
+
});
|
|
1949
|
+
}
|
|
1950
|
+
const updatedAgent = await this.getAgentById({ id });
|
|
1951
|
+
if (!updatedAgent) {
|
|
1952
|
+
throw new error.MastraError({
|
|
1953
|
+
id: storage.createStorageErrorId("LIBSQL", "UPDATE_AGENT", "NOT_FOUND_AFTER_UPDATE"),
|
|
1954
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1955
|
+
category: error.ErrorCategory.SYSTEM,
|
|
1956
|
+
text: `Agent ${id} not found after update`,
|
|
1957
|
+
details: { agentId: id }
|
|
1958
|
+
});
|
|
1609
1959
|
}
|
|
1610
|
-
return
|
|
1960
|
+
return updatedAgent;
|
|
1611
1961
|
} catch (error$1) {
|
|
1612
|
-
|
|
1962
|
+
if (error$1 instanceof error.MastraError) {
|
|
1963
|
+
throw error$1;
|
|
1964
|
+
}
|
|
1965
|
+
throw new error.MastraError(
|
|
1613
1966
|
{
|
|
1614
|
-
id: "
|
|
1967
|
+
id: storage.createStorageErrorId("LIBSQL", "UPDATE_AGENT", "FAILED"),
|
|
1615
1968
|
domain: error.ErrorDomain.STORAGE,
|
|
1616
1969
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1617
|
-
details: {
|
|
1970
|
+
details: { agentId: id }
|
|
1618
1971
|
},
|
|
1619
1972
|
error$1
|
|
1620
1973
|
);
|
|
1621
|
-
this.logger?.trackException?.(mastraError);
|
|
1622
|
-
this.logger?.error?.(mastraError.toString());
|
|
1623
|
-
return [];
|
|
1624
1974
|
}
|
|
1625
1975
|
}
|
|
1626
|
-
async
|
|
1627
|
-
const { resourceId, page = 0, perPage = 100 } = args;
|
|
1628
|
-
const orderBy = this.castThreadOrderBy(args.orderBy);
|
|
1629
|
-
const sortDirection = this.castThreadSortDirection(args.sortDirection);
|
|
1976
|
+
async deleteAgent({ id }) {
|
|
1630
1977
|
try {
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
id: row.id,
|
|
1635
|
-
resourceId: row.resourceId,
|
|
1636
|
-
title: row.title,
|
|
1637
|
-
createdAt: new Date(row.createdAt),
|
|
1638
|
-
// Convert string to Date
|
|
1639
|
-
updatedAt: new Date(row.updatedAt),
|
|
1640
|
-
// Convert string to Date
|
|
1641
|
-
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
1642
|
-
});
|
|
1643
|
-
const currentOffset = page * perPage;
|
|
1644
|
-
const countResult = await this.client.execute({
|
|
1645
|
-
sql: `SELECT COUNT(*) as count ${baseQuery}`,
|
|
1646
|
-
args: queryParams
|
|
1978
|
+
await this.#db.delete({
|
|
1979
|
+
tableName: storage.TABLE_AGENTS,
|
|
1980
|
+
keys: { id }
|
|
1647
1981
|
});
|
|
1648
|
-
|
|
1982
|
+
} catch (error$1) {
|
|
1983
|
+
throw new error.MastraError(
|
|
1984
|
+
{
|
|
1985
|
+
id: storage.createStorageErrorId("LIBSQL", "DELETE_AGENT", "FAILED"),
|
|
1986
|
+
domain: error.ErrorDomain.STORAGE,
|
|
1987
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1988
|
+
details: { agentId: id }
|
|
1989
|
+
},
|
|
1990
|
+
error$1
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
async listAgents(args) {
|
|
1995
|
+
const { page = 0, perPage: perPageInput, orderBy } = args || {};
|
|
1996
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
1997
|
+
if (page < 0) {
|
|
1998
|
+
throw new error.MastraError(
|
|
1999
|
+
{
|
|
2000
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_AGENTS", "INVALID_PAGE"),
|
|
2001
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2002
|
+
category: error.ErrorCategory.USER,
|
|
2003
|
+
details: { page }
|
|
2004
|
+
},
|
|
2005
|
+
new Error("page must be >= 0")
|
|
2006
|
+
);
|
|
2007
|
+
}
|
|
2008
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
2009
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2010
|
+
try {
|
|
2011
|
+
const total = await this.#db.selectTotalCount({ tableName: storage.TABLE_AGENTS });
|
|
1649
2012
|
if (total === 0) {
|
|
1650
2013
|
return {
|
|
1651
|
-
|
|
2014
|
+
agents: [],
|
|
1652
2015
|
total: 0,
|
|
1653
2016
|
page,
|
|
1654
|
-
perPage,
|
|
2017
|
+
perPage: perPageForResponse,
|
|
1655
2018
|
hasMore: false
|
|
1656
2019
|
};
|
|
1657
2020
|
}
|
|
1658
|
-
const
|
|
1659
|
-
|
|
1660
|
-
|
|
2021
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2022
|
+
const rows = await this.#db.selectMany({
|
|
2023
|
+
tableName: storage.TABLE_AGENTS,
|
|
2024
|
+
orderBy: `"${field}" ${direction}`,
|
|
2025
|
+
limit: limitValue,
|
|
2026
|
+
offset
|
|
1661
2027
|
});
|
|
1662
|
-
const
|
|
2028
|
+
const agents = rows.map((row) => this.parseRow(row));
|
|
1663
2029
|
return {
|
|
1664
|
-
|
|
2030
|
+
agents,
|
|
1665
2031
|
total,
|
|
1666
2032
|
page,
|
|
1667
|
-
perPage,
|
|
1668
|
-
hasMore:
|
|
2033
|
+
perPage: perPageForResponse,
|
|
2034
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
1669
2035
|
};
|
|
1670
2036
|
} catch (error$1) {
|
|
1671
|
-
|
|
2037
|
+
throw new error.MastraError(
|
|
1672
2038
|
{
|
|
1673
|
-
id: "
|
|
2039
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_AGENTS", "FAILED"),
|
|
1674
2040
|
domain: error.ErrorDomain.STORAGE,
|
|
1675
|
-
category: error.ErrorCategory.THIRD_PARTY
|
|
1676
|
-
details: { resourceId }
|
|
2041
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1677
2042
|
},
|
|
1678
2043
|
error$1
|
|
1679
2044
|
);
|
|
1680
|
-
this.logger?.trackException?.(mastraError);
|
|
1681
|
-
this.logger?.error?.(mastraError.toString());
|
|
1682
|
-
return { threads: [], total: 0, page, perPage, hasMore: false };
|
|
1683
2045
|
}
|
|
1684
2046
|
}
|
|
1685
|
-
|
|
2047
|
+
};
|
|
2048
|
+
var MemoryLibSQL = class extends storage.MemoryStorage {
|
|
2049
|
+
#client;
|
|
2050
|
+
#db;
|
|
2051
|
+
constructor(config) {
|
|
2052
|
+
super();
|
|
2053
|
+
const client = resolveClient(config);
|
|
2054
|
+
this.#client = client;
|
|
2055
|
+
this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
|
|
2056
|
+
}
|
|
2057
|
+
async init() {
|
|
2058
|
+
await this.#db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
|
|
2059
|
+
await this.#db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
|
|
2060
|
+
await this.#db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
|
|
2061
|
+
await this.#db.alterTable({
|
|
2062
|
+
tableName: storage.TABLE_MESSAGES,
|
|
2063
|
+
schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES],
|
|
2064
|
+
ifNotExists: ["resourceId"]
|
|
2065
|
+
});
|
|
2066
|
+
}
|
|
2067
|
+
async dangerouslyClearAll() {
|
|
2068
|
+
await this.#db.deleteData({ tableName: storage.TABLE_MESSAGES });
|
|
2069
|
+
await this.#db.deleteData({ tableName: storage.TABLE_THREADS });
|
|
2070
|
+
await this.#db.deleteData({ tableName: storage.TABLE_RESOURCES });
|
|
2071
|
+
}
|
|
2072
|
+
parseRow(row) {
|
|
2073
|
+
let content = row.content;
|
|
1686
2074
|
try {
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
2075
|
+
content = JSON.parse(row.content);
|
|
2076
|
+
} catch {
|
|
2077
|
+
}
|
|
2078
|
+
const result = {
|
|
2079
|
+
id: row.id,
|
|
2080
|
+
content,
|
|
2081
|
+
role: row.role,
|
|
2082
|
+
createdAt: new Date(row.createdAt),
|
|
2083
|
+
threadId: row.thread_id,
|
|
2084
|
+
resourceId: row.resourceId
|
|
2085
|
+
};
|
|
2086
|
+
if (row.type && row.type !== `v2`) result.type = row.type;
|
|
2087
|
+
return result;
|
|
2088
|
+
}
|
|
2089
|
+
async _getIncludedMessages({ include }) {
|
|
2090
|
+
if (!include || include.length === 0) return null;
|
|
2091
|
+
const unionQueries = [];
|
|
2092
|
+
const params = [];
|
|
2093
|
+
for (const inc of include) {
|
|
2094
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
2095
|
+
unionQueries.push(
|
|
2096
|
+
`
|
|
2097
|
+
SELECT * FROM (
|
|
2098
|
+
WITH target_thread AS (
|
|
2099
|
+
SELECT thread_id FROM "${storage.TABLE_MESSAGES}" WHERE id = ?
|
|
2100
|
+
),
|
|
2101
|
+
numbered_messages AS (
|
|
2102
|
+
SELECT
|
|
2103
|
+
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
2104
|
+
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
2105
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
2106
|
+
WHERE thread_id = (SELECT thread_id FROM target_thread)
|
|
2107
|
+
),
|
|
2108
|
+
target_positions AS (
|
|
2109
|
+
SELECT row_num as target_pos
|
|
2110
|
+
FROM numbered_messages
|
|
2111
|
+
WHERE id = ?
|
|
2112
|
+
)
|
|
2113
|
+
SELECT DISTINCT m.*
|
|
2114
|
+
FROM numbered_messages m
|
|
2115
|
+
CROSS JOIN target_positions t
|
|
2116
|
+
WHERE m.row_num BETWEEN (t.target_pos - ?) AND (t.target_pos + ?)
|
|
2117
|
+
)
|
|
2118
|
+
`
|
|
2119
|
+
// Keep ASC for final sorting after fetching context
|
|
2120
|
+
);
|
|
2121
|
+
params.push(id, id, withPreviousMessages, withNextMessages);
|
|
2122
|
+
}
|
|
2123
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
2124
|
+
const includedResult = await this.#client.execute({ sql: finalQuery, args: params });
|
|
2125
|
+
const includedRows = includedResult.rows?.map((row) => this.parseRow(row));
|
|
2126
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2127
|
+
const dedupedRows = includedRows.filter((row) => {
|
|
2128
|
+
if (seen.has(row.id)) return false;
|
|
2129
|
+
seen.add(row.id);
|
|
2130
|
+
return true;
|
|
2131
|
+
});
|
|
2132
|
+
return dedupedRows;
|
|
2133
|
+
}
|
|
2134
|
+
async listMessagesById({ messageIds }) {
|
|
2135
|
+
if (messageIds.length === 0) return { messages: [] };
|
|
2136
|
+
try {
|
|
2137
|
+
const sql = `
|
|
2138
|
+
SELECT
|
|
2139
|
+
id,
|
|
2140
|
+
content,
|
|
2141
|
+
role,
|
|
2142
|
+
type,
|
|
2143
|
+
"createdAt",
|
|
2144
|
+
thread_id,
|
|
2145
|
+
"resourceId"
|
|
2146
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
2147
|
+
WHERE id IN (${messageIds.map(() => "?").join(", ")})
|
|
2148
|
+
ORDER BY "createdAt" DESC
|
|
2149
|
+
`;
|
|
2150
|
+
const result = await this.#client.execute({ sql, args: messageIds });
|
|
2151
|
+
if (!result.rows) return { messages: [] };
|
|
2152
|
+
const list = new agent.MessageList().add(result.rows.map(this.parseRow), "memory");
|
|
2153
|
+
return { messages: list.get.all.db() };
|
|
1695
2154
|
} catch (error$1) {
|
|
1696
|
-
|
|
2155
|
+
throw new error.MastraError(
|
|
1697
2156
|
{
|
|
1698
|
-
id: "
|
|
2157
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_MESSAGES_BY_ID", "FAILED"),
|
|
1699
2158
|
domain: error.ErrorDomain.STORAGE,
|
|
1700
2159
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1701
|
-
details: {
|
|
2160
|
+
details: { messageIds: JSON.stringify(messageIds) }
|
|
1702
2161
|
},
|
|
1703
2162
|
error$1
|
|
1704
2163
|
);
|
|
1705
|
-
this.logger?.trackException?.(mastraError);
|
|
1706
|
-
this.logger?.error?.(mastraError.toString());
|
|
1707
|
-
throw mastraError;
|
|
1708
2164
|
}
|
|
1709
2165
|
}
|
|
1710
|
-
async
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
}) {
|
|
1715
|
-
const thread = await this.getThreadById({ threadId: id });
|
|
1716
|
-
if (!thread) {
|
|
1717
|
-
throw new error.MastraError({
|
|
1718
|
-
id: "LIBSQL_STORE_UPDATE_THREAD_FAILED_THREAD_NOT_FOUND",
|
|
1719
|
-
domain: error.ErrorDomain.STORAGE,
|
|
1720
|
-
category: error.ErrorCategory.USER,
|
|
1721
|
-
text: `Thread ${id} not found`,
|
|
1722
|
-
details: {
|
|
1723
|
-
status: 404,
|
|
1724
|
-
threadId: id
|
|
1725
|
-
}
|
|
1726
|
-
});
|
|
1727
|
-
}
|
|
1728
|
-
const updatedThread = {
|
|
1729
|
-
...thread,
|
|
1730
|
-
title,
|
|
1731
|
-
metadata: {
|
|
1732
|
-
...thread.metadata,
|
|
1733
|
-
...metadata
|
|
1734
|
-
}
|
|
1735
|
-
};
|
|
1736
|
-
try {
|
|
1737
|
-
await this.client.execute({
|
|
1738
|
-
sql: `UPDATE ${storage.TABLE_THREADS} SET title = ?, metadata = ? WHERE id = ?`,
|
|
1739
|
-
args: [title, JSON.stringify(updatedThread.metadata), id]
|
|
1740
|
-
});
|
|
1741
|
-
return updatedThread;
|
|
1742
|
-
} catch (error$1) {
|
|
2166
|
+
async listMessages(args) {
|
|
2167
|
+
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
2168
|
+
const threadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
2169
|
+
if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
|
|
1743
2170
|
throw new error.MastraError(
|
|
1744
2171
|
{
|
|
1745
|
-
id: "
|
|
2172
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_MESSAGES", "INVALID_THREAD_ID"),
|
|
1746
2173
|
domain: error.ErrorDomain.STORAGE,
|
|
1747
2174
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1748
|
-
|
|
1749
|
-
details: { threadId: id }
|
|
2175
|
+
details: { threadId: Array.isArray(threadId) ? threadId.join(",") : threadId }
|
|
1750
2176
|
},
|
|
1751
|
-
|
|
2177
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
1752
2178
|
);
|
|
1753
2179
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
2180
|
+
if (page < 0) {
|
|
2181
|
+
throw new error.MastraError(
|
|
2182
|
+
{
|
|
2183
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_MESSAGES", "INVALID_PAGE"),
|
|
2184
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2185
|
+
category: error.ErrorCategory.USER,
|
|
2186
|
+
details: { page }
|
|
2187
|
+
},
|
|
2188
|
+
new Error("page must be >= 0")
|
|
2189
|
+
);
|
|
2190
|
+
}
|
|
2191
|
+
const perPage = storage.normalizePerPage(perPageInput, 40);
|
|
2192
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
1756
2193
|
try {
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
2194
|
+
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
2195
|
+
const orderByStatement = `ORDER BY "${field}" ${direction}`;
|
|
2196
|
+
const threadPlaceholders = threadIds.map(() => "?").join(", ");
|
|
2197
|
+
const conditions = [`thread_id IN (${threadPlaceholders})`];
|
|
2198
|
+
const queryParams = [...threadIds];
|
|
2199
|
+
if (resourceId) {
|
|
2200
|
+
conditions.push(`"resourceId" = ?`);
|
|
2201
|
+
queryParams.push(resourceId);
|
|
2202
|
+
}
|
|
2203
|
+
if (filter?.dateRange?.start) {
|
|
2204
|
+
conditions.push(`"createdAt" >= ?`);
|
|
2205
|
+
queryParams.push(
|
|
2206
|
+
filter.dateRange.start instanceof Date ? filter.dateRange.start.toISOString() : filter.dateRange.start
|
|
2207
|
+
);
|
|
2208
|
+
}
|
|
2209
|
+
if (filter?.dateRange?.end) {
|
|
2210
|
+
conditions.push(`"createdAt" <= ?`);
|
|
2211
|
+
queryParams.push(
|
|
2212
|
+
filter.dateRange.end instanceof Date ? filter.dateRange.end.toISOString() : filter.dateRange.end
|
|
2213
|
+
);
|
|
2214
|
+
}
|
|
2215
|
+
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2216
|
+
const countResult = await this.#client.execute({
|
|
2217
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_MESSAGES} ${whereClause}`,
|
|
2218
|
+
args: queryParams
|
|
1760
2219
|
});
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
2220
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
2221
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2222
|
+
const dataResult = await this.#client.execute({
|
|
2223
|
+
sql: `SELECT id, content, role, type, "createdAt", "resourceId", "thread_id" FROM ${storage.TABLE_MESSAGES} ${whereClause} ${orderByStatement} LIMIT ? OFFSET ?`,
|
|
2224
|
+
args: [...queryParams, limitValue, offset]
|
|
2225
|
+
});
|
|
2226
|
+
const messages = (dataResult.rows || []).map((row) => this.parseRow(row));
|
|
2227
|
+
if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
|
|
2228
|
+
return {
|
|
2229
|
+
messages: [],
|
|
2230
|
+
total: 0,
|
|
2231
|
+
page,
|
|
2232
|
+
perPage: perPageForResponse,
|
|
2233
|
+
hasMore: false
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
const messageIds = new Set(messages.map((m) => m.id));
|
|
2237
|
+
if (include && include.length > 0) {
|
|
2238
|
+
const includeMessages = await this._getIncludedMessages({ include });
|
|
2239
|
+
if (includeMessages) {
|
|
2240
|
+
for (const includeMsg of includeMessages) {
|
|
2241
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
2242
|
+
messages.push(includeMsg);
|
|
2243
|
+
messageIds.add(includeMsg.id);
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
}
|
|
2248
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
2249
|
+
let finalMessages = list.get.all.db();
|
|
2250
|
+
finalMessages = finalMessages.sort((a, b) => {
|
|
2251
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
2252
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
2253
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
2254
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
2255
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
2256
|
+
}
|
|
2257
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
1764
2258
|
});
|
|
2259
|
+
const threadIdSet = new Set(threadIds);
|
|
2260
|
+
const returnedThreadMessageIds = new Set(
|
|
2261
|
+
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
2262
|
+
);
|
|
2263
|
+
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
2264
|
+
const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
|
|
2265
|
+
return {
|
|
2266
|
+
messages: finalMessages,
|
|
2267
|
+
total,
|
|
2268
|
+
page,
|
|
2269
|
+
perPage: perPageForResponse,
|
|
2270
|
+
hasMore
|
|
2271
|
+
};
|
|
1765
2272
|
} catch (error$1) {
|
|
1766
|
-
|
|
2273
|
+
const mastraError = new error.MastraError(
|
|
1767
2274
|
{
|
|
1768
|
-
id: "
|
|
2275
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_MESSAGES", "FAILED"),
|
|
1769
2276
|
domain: error.ErrorDomain.STORAGE,
|
|
1770
2277
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
1771
|
-
details: {
|
|
2278
|
+
details: {
|
|
2279
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
2280
|
+
resourceId: resourceId ?? ""
|
|
2281
|
+
}
|
|
1772
2282
|
},
|
|
1773
2283
|
error$1
|
|
1774
2284
|
);
|
|
2285
|
+
this.logger?.error?.(mastraError.toString());
|
|
2286
|
+
this.logger?.trackException?.(mastraError);
|
|
2287
|
+
return {
|
|
2288
|
+
messages: [],
|
|
2289
|
+
total: 0,
|
|
2290
|
+
page,
|
|
2291
|
+
perPage: perPageForResponse,
|
|
2292
|
+
hasMore: false
|
|
2293
|
+
};
|
|
1775
2294
|
}
|
|
1776
2295
|
}
|
|
1777
|
-
}
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
if (error.message && (error.message.includes("SQLITE_BUSY") || error.message.includes("database is locked")) && retries < maxRetries) {
|
|
1790
|
-
retries++;
|
|
1791
|
-
const backoffTime = initialBackoffMs * Math.pow(2, retries - 1);
|
|
1792
|
-
logger.warn(
|
|
1793
|
-
`LibSQLStore: Encountered SQLITE_BUSY during ${operationDescription}. Retrying (${retries}/${maxRetries}) in ${backoffTime}ms...`
|
|
2296
|
+
async saveMessages({ messages }) {
|
|
2297
|
+
if (messages.length === 0) return { messages };
|
|
2298
|
+
try {
|
|
2299
|
+
const threadId = messages[0]?.threadId;
|
|
2300
|
+
if (!threadId) {
|
|
2301
|
+
throw new Error("Thread ID is required");
|
|
2302
|
+
}
|
|
2303
|
+
const batchStatements = messages.map((message) => {
|
|
2304
|
+
const time = message.createdAt || /* @__PURE__ */ new Date();
|
|
2305
|
+
if (!message.threadId) {
|
|
2306
|
+
throw new Error(
|
|
2307
|
+
`Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
|
|
1794
2308
|
);
|
|
1795
|
-
await new Promise((resolve) => setTimeout(resolve, backoffTime));
|
|
1796
|
-
} else {
|
|
1797
|
-
logger.error(`LibSQLStore: Error during ${operationDescription} after ${retries} retries: ${error}`);
|
|
1798
|
-
throw error;
|
|
1799
2309
|
}
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
2310
|
+
if (!message.resourceId) {
|
|
2311
|
+
throw new Error(
|
|
2312
|
+
`Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
return {
|
|
2316
|
+
sql: `INSERT INTO "${storage.TABLE_MESSAGES}" (id, thread_id, content, role, type, "createdAt", "resourceId")
|
|
2317
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2318
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
2319
|
+
thread_id=excluded.thread_id,
|
|
2320
|
+
content=excluded.content,
|
|
2321
|
+
role=excluded.role,
|
|
2322
|
+
type=excluded.type,
|
|
2323
|
+
"resourceId"=excluded."resourceId"
|
|
2324
|
+
`,
|
|
2325
|
+
args: [
|
|
2326
|
+
message.id,
|
|
2327
|
+
message.threadId,
|
|
2328
|
+
typeof message.content === "object" ? JSON.stringify(message.content) : message.content,
|
|
2329
|
+
message.role,
|
|
2330
|
+
message.type || "v2",
|
|
2331
|
+
time instanceof Date ? time.toISOString() : time,
|
|
2332
|
+
message.resourceId
|
|
2333
|
+
]
|
|
2334
|
+
};
|
|
2335
|
+
});
|
|
2336
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2337
|
+
batchStatements.push({
|
|
2338
|
+
sql: `UPDATE "${storage.TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
|
|
2339
|
+
args: [now, threadId]
|
|
2340
|
+
});
|
|
2341
|
+
const BATCH_SIZE = 50;
|
|
2342
|
+
const messageStatements = batchStatements.slice(0, -1);
|
|
2343
|
+
const threadUpdateStatement = batchStatements[batchStatements.length - 1];
|
|
2344
|
+
for (let i = 0; i < messageStatements.length; i += BATCH_SIZE) {
|
|
2345
|
+
const batch = messageStatements.slice(i, i + BATCH_SIZE);
|
|
2346
|
+
if (batch.length > 0) {
|
|
2347
|
+
await this.#client.batch(batch, "write");
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
if (threadUpdateStatement) {
|
|
2351
|
+
await this.#client.execute(threadUpdateStatement);
|
|
2352
|
+
}
|
|
2353
|
+
const list = new agent.MessageList().add(messages, "memory");
|
|
2354
|
+
return { messages: list.get.all.db() };
|
|
2355
|
+
} catch (error$1) {
|
|
2356
|
+
throw new error.MastraError(
|
|
2357
|
+
{
|
|
2358
|
+
id: storage.createStorageErrorId("LIBSQL", "SAVE_MESSAGES", "FAILED"),
|
|
2359
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2360
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2361
|
+
},
|
|
2362
|
+
error$1
|
|
2363
|
+
);
|
|
1813
2364
|
}
|
|
1814
|
-
return typeof v === "object" ? JSON.stringify(v) : v;
|
|
1815
|
-
});
|
|
1816
|
-
const placeholders = values.map(() => "?").join(", ");
|
|
1817
|
-
return {
|
|
1818
|
-
sql: `INSERT OR REPLACE INTO ${parsedTableName} (${columns.join(", ")}) VALUES (${placeholders})`,
|
|
1819
|
-
args: values
|
|
1820
|
-
};
|
|
1821
|
-
}
|
|
1822
|
-
function prepareUpdateStatement({
|
|
1823
|
-
tableName,
|
|
1824
|
-
updates,
|
|
1825
|
-
keys
|
|
1826
|
-
}) {
|
|
1827
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
1828
|
-
const schema = storage.TABLE_SCHEMAS[tableName];
|
|
1829
|
-
const updateColumns = Object.keys(updates).map((col) => utils.parseSqlIdentifier(col, "column name"));
|
|
1830
|
-
const updateValues = Object.values(updates).map(transformToSqlValue);
|
|
1831
|
-
const setClause = updateColumns.map((col) => `${col} = ?`).join(", ");
|
|
1832
|
-
const whereClause = prepareWhereClause(keys, schema);
|
|
1833
|
-
return {
|
|
1834
|
-
sql: `UPDATE ${parsedTableName} SET ${setClause}${whereClause.sql}`,
|
|
1835
|
-
args: [...updateValues, ...whereClause.args]
|
|
1836
|
-
};
|
|
1837
|
-
}
|
|
1838
|
-
function transformToSqlValue(value) {
|
|
1839
|
-
if (typeof value === "undefined" || value === null) {
|
|
1840
|
-
return null;
|
|
1841
|
-
}
|
|
1842
|
-
if (value instanceof Date) {
|
|
1843
|
-
return value.toISOString();
|
|
1844
2365
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
return {
|
|
1851
|
-
sql: `DELETE FROM ${parsedTableName}${whereClause.sql}`,
|
|
1852
|
-
args: whereClause.args
|
|
1853
|
-
};
|
|
1854
|
-
}
|
|
1855
|
-
function prepareWhereClause(filters, schema) {
|
|
1856
|
-
const conditions = [];
|
|
1857
|
-
const args = [];
|
|
1858
|
-
for (const [columnName, filterValue] of Object.entries(filters)) {
|
|
1859
|
-
const column = schema[columnName];
|
|
1860
|
-
if (!column) {
|
|
1861
|
-
throw new Error(`Unknown column: ${columnName}`);
|
|
2366
|
+
async updateMessages({
|
|
2367
|
+
messages
|
|
2368
|
+
}) {
|
|
2369
|
+
if (messages.length === 0) {
|
|
2370
|
+
return [];
|
|
1862
2371
|
}
|
|
1863
|
-
const
|
|
1864
|
-
const
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
args
|
|
1871
|
-
};
|
|
1872
|
-
}
|
|
1873
|
-
function buildCondition2(columnName, filterValue) {
|
|
1874
|
-
if (filterValue === null) {
|
|
1875
|
-
return { condition: `${columnName} IS NULL`, args: [] };
|
|
1876
|
-
}
|
|
1877
|
-
if (typeof filterValue === "object" && filterValue !== null && ("startAt" in filterValue || "endAt" in filterValue)) {
|
|
1878
|
-
return buildDateRangeCondition(columnName, filterValue);
|
|
1879
|
-
}
|
|
1880
|
-
return {
|
|
1881
|
-
condition: `${columnName} = ?`,
|
|
1882
|
-
args: [transformToSqlValue(filterValue)]
|
|
1883
|
-
};
|
|
1884
|
-
}
|
|
1885
|
-
function buildDateRangeCondition(columnName, range) {
|
|
1886
|
-
const conditions = [];
|
|
1887
|
-
const args = [];
|
|
1888
|
-
if (range.startAt !== void 0) {
|
|
1889
|
-
conditions.push(`${columnName} >= ?`);
|
|
1890
|
-
args.push(transformToSqlValue(range.startAt));
|
|
1891
|
-
}
|
|
1892
|
-
if (range.endAt !== void 0) {
|
|
1893
|
-
conditions.push(`${columnName} <= ?`);
|
|
1894
|
-
args.push(transformToSqlValue(range.endAt));
|
|
1895
|
-
}
|
|
1896
|
-
if (conditions.length === 0) {
|
|
1897
|
-
throw new Error("Date range must specify at least startAt or endAt");
|
|
1898
|
-
}
|
|
1899
|
-
return {
|
|
1900
|
-
condition: conditions.join(" AND "),
|
|
1901
|
-
args
|
|
1902
|
-
};
|
|
1903
|
-
}
|
|
1904
|
-
function buildDateRangeFilter(dateRange, columnName = "createdAt") {
|
|
1905
|
-
if (!dateRange?.start && !dateRange?.end) {
|
|
1906
|
-
return {};
|
|
1907
|
-
}
|
|
1908
|
-
const filter = {};
|
|
1909
|
-
if (dateRange.start) {
|
|
1910
|
-
filter.startAt = new Date(dateRange.start).toISOString();
|
|
1911
|
-
}
|
|
1912
|
-
if (dateRange.end) {
|
|
1913
|
-
filter.endAt = new Date(dateRange.end).toISOString();
|
|
1914
|
-
}
|
|
1915
|
-
return { [columnName]: filter };
|
|
1916
|
-
}
|
|
1917
|
-
function transformFromSqlRow({
|
|
1918
|
-
tableName,
|
|
1919
|
-
sqlRow
|
|
1920
|
-
}) {
|
|
1921
|
-
const result = {};
|
|
1922
|
-
const jsonColumns = new Set(
|
|
1923
|
-
Object.keys(storage.TABLE_SCHEMAS[tableName]).filter((key) => storage.TABLE_SCHEMAS[tableName][key].type === "jsonb").map((key) => key)
|
|
1924
|
-
);
|
|
1925
|
-
const dateColumns = new Set(
|
|
1926
|
-
Object.keys(storage.TABLE_SCHEMAS[tableName]).filter((key) => storage.TABLE_SCHEMAS[tableName][key].type === "timestamp").map((key) => key)
|
|
1927
|
-
);
|
|
1928
|
-
for (const [key, value] of Object.entries(sqlRow)) {
|
|
1929
|
-
if (value === null || value === void 0) {
|
|
1930
|
-
result[key] = value;
|
|
1931
|
-
continue;
|
|
2372
|
+
const messageIds = messages.map((m) => m.id);
|
|
2373
|
+
const placeholders = messageIds.map(() => "?").join(",");
|
|
2374
|
+
const selectSql = `SELECT * FROM ${storage.TABLE_MESSAGES} WHERE id IN (${placeholders})`;
|
|
2375
|
+
const existingResult = await this.#client.execute({ sql: selectSql, args: messageIds });
|
|
2376
|
+
const existingMessages = existingResult.rows.map((row) => this.parseRow(row));
|
|
2377
|
+
if (existingMessages.length === 0) {
|
|
2378
|
+
return [];
|
|
1932
2379
|
}
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
2380
|
+
const batchStatements = [];
|
|
2381
|
+
const threadIdsToUpdate = /* @__PURE__ */ new Set();
|
|
2382
|
+
const columnMapping = {
|
|
2383
|
+
threadId: "thread_id"
|
|
2384
|
+
};
|
|
2385
|
+
for (const existingMessage of existingMessages) {
|
|
2386
|
+
const updatePayload = messages.find((m) => m.id === existingMessage.id);
|
|
2387
|
+
if (!updatePayload) continue;
|
|
2388
|
+
const { id, ...fieldsToUpdate } = updatePayload;
|
|
2389
|
+
if (Object.keys(fieldsToUpdate).length === 0) continue;
|
|
2390
|
+
threadIdsToUpdate.add(existingMessage.threadId);
|
|
2391
|
+
if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
|
|
2392
|
+
threadIdsToUpdate.add(updatePayload.threadId);
|
|
2393
|
+
}
|
|
2394
|
+
const setClauses = [];
|
|
2395
|
+
const args = [];
|
|
2396
|
+
const updatableFields = { ...fieldsToUpdate };
|
|
2397
|
+
if (updatableFields.content) {
|
|
2398
|
+
const newContent = {
|
|
2399
|
+
...existingMessage.content,
|
|
2400
|
+
...updatableFields.content,
|
|
2401
|
+
// Deep merge metadata if it exists on both
|
|
2402
|
+
...existingMessage.content?.metadata && updatableFields.content.metadata ? {
|
|
2403
|
+
metadata: {
|
|
2404
|
+
...existingMessage.content.metadata,
|
|
2405
|
+
...updatableFields.content.metadata
|
|
2406
|
+
}
|
|
2407
|
+
} : {}
|
|
2408
|
+
};
|
|
2409
|
+
setClauses.push(`${utils.parseSqlIdentifier("content", "column name")} = ?`);
|
|
2410
|
+
args.push(JSON.stringify(newContent));
|
|
2411
|
+
delete updatableFields.content;
|
|
2412
|
+
}
|
|
2413
|
+
for (const key in updatableFields) {
|
|
2414
|
+
if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
|
|
2415
|
+
const dbKey = columnMapping[key] || key;
|
|
2416
|
+
setClauses.push(`${utils.parseSqlIdentifier(dbKey, "column name")} = ?`);
|
|
2417
|
+
let value = updatableFields[key];
|
|
2418
|
+
if (typeof value === "object" && value !== null) {
|
|
2419
|
+
value = JSON.stringify(value);
|
|
2420
|
+
}
|
|
2421
|
+
args.push(value);
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
if (setClauses.length === 0) continue;
|
|
2425
|
+
args.push(id);
|
|
2426
|
+
const sql = `UPDATE ${storage.TABLE_MESSAGES} SET ${setClauses.join(", ")} WHERE id = ?`;
|
|
2427
|
+
batchStatements.push({ sql, args });
|
|
1936
2428
|
}
|
|
1937
|
-
if (
|
|
1938
|
-
|
|
1939
|
-
continue;
|
|
2429
|
+
if (batchStatements.length === 0) {
|
|
2430
|
+
return existingMessages;
|
|
1940
2431
|
}
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
this.
|
|
2432
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2433
|
+
for (const threadId of threadIdsToUpdate) {
|
|
2434
|
+
if (threadId) {
|
|
2435
|
+
batchStatements.push({
|
|
2436
|
+
sql: `UPDATE ${storage.TABLE_THREADS} SET updatedAt = ? WHERE id = ?`,
|
|
2437
|
+
args: [now, threadId]
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
await this.#client.batch(batchStatements, "write");
|
|
2442
|
+
const updatedResult = await this.#client.execute({ sql: selectSql, args: messageIds });
|
|
2443
|
+
return updatedResult.rows.map((row) => this.parseRow(row));
|
|
1952
2444
|
}
|
|
1953
|
-
async
|
|
2445
|
+
async deleteMessages(messageIds) {
|
|
2446
|
+
if (!messageIds || messageIds.length === 0) {
|
|
2447
|
+
return;
|
|
2448
|
+
}
|
|
1954
2449
|
try {
|
|
1955
|
-
const
|
|
1956
|
-
const
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2450
|
+
const BATCH_SIZE = 100;
|
|
2451
|
+
const threadIds = /* @__PURE__ */ new Set();
|
|
2452
|
+
const tx = await this.#client.transaction("write");
|
|
2453
|
+
try {
|
|
2454
|
+
for (let i = 0; i < messageIds.length; i += BATCH_SIZE) {
|
|
2455
|
+
const batch = messageIds.slice(i, i + BATCH_SIZE);
|
|
2456
|
+
const placeholders = batch.map(() => "?").join(",");
|
|
2457
|
+
const result = await tx.execute({
|
|
2458
|
+
sql: `SELECT DISTINCT thread_id FROM "${storage.TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
|
|
2459
|
+
args: batch
|
|
2460
|
+
});
|
|
2461
|
+
result.rows?.forEach((row) => {
|
|
2462
|
+
if (row.thread_id) threadIds.add(row.thread_id);
|
|
2463
|
+
});
|
|
2464
|
+
await tx.execute({
|
|
2465
|
+
sql: `DELETE FROM "${storage.TABLE_MESSAGES}" WHERE id IN (${placeholders})`,
|
|
2466
|
+
args: batch
|
|
2467
|
+
});
|
|
2468
|
+
}
|
|
2469
|
+
if (threadIds.size > 0) {
|
|
2470
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2471
|
+
for (const threadId of threadIds) {
|
|
2472
|
+
await tx.execute({
|
|
2473
|
+
sql: `UPDATE "${storage.TABLE_THREADS}" SET "updatedAt" = ? WHERE id = ?`,
|
|
2474
|
+
args: [now, threadId]
|
|
2475
|
+
});
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
await tx.commit();
|
|
2479
|
+
} catch (error) {
|
|
2480
|
+
await tx.rollback();
|
|
2481
|
+
throw error;
|
|
2482
|
+
}
|
|
1962
2483
|
} catch (error$1) {
|
|
1963
2484
|
throw new error.MastraError(
|
|
1964
2485
|
{
|
|
1965
|
-
id: "
|
|
2486
|
+
id: storage.createStorageErrorId("LIBSQL", "DELETE_MESSAGES", "FAILED"),
|
|
1966
2487
|
domain: error.ErrorDomain.STORAGE,
|
|
1967
|
-
category: error.ErrorCategory.
|
|
1968
|
-
details: {
|
|
1969
|
-
spanId: span.spanId,
|
|
1970
|
-
traceId: span.traceId,
|
|
1971
|
-
spanType: span.spanType,
|
|
1972
|
-
spanName: span.name
|
|
1973
|
-
}
|
|
2488
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2489
|
+
details: { messageIds: messageIds.join(", ") }
|
|
1974
2490
|
},
|
|
1975
2491
|
error$1
|
|
1976
2492
|
);
|
|
1977
2493
|
}
|
|
1978
2494
|
}
|
|
1979
|
-
async
|
|
2495
|
+
async getResourceById({ resourceId }) {
|
|
2496
|
+
const result = await this.#db.select({
|
|
2497
|
+
tableName: storage.TABLE_RESOURCES,
|
|
2498
|
+
keys: { id: resourceId }
|
|
2499
|
+
});
|
|
2500
|
+
if (!result) {
|
|
2501
|
+
return null;
|
|
2502
|
+
}
|
|
2503
|
+
return {
|
|
2504
|
+
...result,
|
|
2505
|
+
// Ensure workingMemory is always returned as a string, even if auto-parsed as JSON
|
|
2506
|
+
workingMemory: result.workingMemory && typeof result.workingMemory === "object" ? JSON.stringify(result.workingMemory) : result.workingMemory,
|
|
2507
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata,
|
|
2508
|
+
createdAt: new Date(result.createdAt),
|
|
2509
|
+
updatedAt: new Date(result.updatedAt)
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
async saveResource({ resource }) {
|
|
2513
|
+
await this.#db.insert({
|
|
2514
|
+
tableName: storage.TABLE_RESOURCES,
|
|
2515
|
+
record: {
|
|
2516
|
+
...resource,
|
|
2517
|
+
metadata: JSON.stringify(resource.metadata)
|
|
2518
|
+
}
|
|
2519
|
+
});
|
|
2520
|
+
return resource;
|
|
2521
|
+
}
|
|
2522
|
+
async updateResource({
|
|
2523
|
+
resourceId,
|
|
2524
|
+
workingMemory,
|
|
2525
|
+
metadata
|
|
2526
|
+
}) {
|
|
2527
|
+
const existingResource = await this.getResourceById({ resourceId });
|
|
2528
|
+
if (!existingResource) {
|
|
2529
|
+
const newResource = {
|
|
2530
|
+
id: resourceId,
|
|
2531
|
+
workingMemory,
|
|
2532
|
+
metadata: metadata || {},
|
|
2533
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
2534
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2535
|
+
};
|
|
2536
|
+
return this.saveResource({ resource: newResource });
|
|
2537
|
+
}
|
|
2538
|
+
const updatedResource = {
|
|
2539
|
+
...existingResource,
|
|
2540
|
+
workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
|
|
2541
|
+
metadata: {
|
|
2542
|
+
...existingResource.metadata,
|
|
2543
|
+
...metadata
|
|
2544
|
+
},
|
|
2545
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2546
|
+
};
|
|
2547
|
+
const updates = [];
|
|
2548
|
+
const values = [];
|
|
2549
|
+
if (workingMemory !== void 0) {
|
|
2550
|
+
updates.push("workingMemory = ?");
|
|
2551
|
+
values.push(workingMemory);
|
|
2552
|
+
}
|
|
2553
|
+
if (metadata) {
|
|
2554
|
+
updates.push("metadata = ?");
|
|
2555
|
+
values.push(JSON.stringify(updatedResource.metadata));
|
|
2556
|
+
}
|
|
2557
|
+
updates.push("updatedAt = ?");
|
|
2558
|
+
values.push(updatedResource.updatedAt.toISOString());
|
|
2559
|
+
values.push(resourceId);
|
|
2560
|
+
await this.#client.execute({
|
|
2561
|
+
sql: `UPDATE ${storage.TABLE_RESOURCES} SET ${updates.join(", ")} WHERE id = ?`,
|
|
2562
|
+
args: values
|
|
2563
|
+
});
|
|
2564
|
+
return updatedResource;
|
|
2565
|
+
}
|
|
2566
|
+
async getThreadById({ threadId }) {
|
|
1980
2567
|
try {
|
|
1981
|
-
const
|
|
1982
|
-
tableName: storage.
|
|
1983
|
-
|
|
1984
|
-
orderBy: "startedAt DESC"
|
|
2568
|
+
const result = await this.#db.select({
|
|
2569
|
+
tableName: storage.TABLE_THREADS,
|
|
2570
|
+
keys: { id: threadId }
|
|
1985
2571
|
});
|
|
1986
|
-
if (!
|
|
2572
|
+
if (!result) {
|
|
1987
2573
|
return null;
|
|
1988
2574
|
}
|
|
1989
2575
|
return {
|
|
1990
|
-
|
|
1991
|
-
|
|
2576
|
+
...result,
|
|
2577
|
+
metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata,
|
|
2578
|
+
createdAt: new Date(result.createdAt),
|
|
2579
|
+
updatedAt: new Date(result.updatedAt)
|
|
1992
2580
|
};
|
|
1993
2581
|
} catch (error$1) {
|
|
1994
2582
|
throw new error.MastraError(
|
|
1995
2583
|
{
|
|
1996
|
-
id: "
|
|
2584
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_THREAD_BY_ID", "FAILED"),
|
|
1997
2585
|
domain: error.ErrorDomain.STORAGE,
|
|
1998
|
-
category: error.ErrorCategory.
|
|
1999
|
-
details: {
|
|
2000
|
-
traceId
|
|
2001
|
-
}
|
|
2586
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2587
|
+
details: { threadId }
|
|
2002
2588
|
},
|
|
2003
2589
|
error$1
|
|
2004
2590
|
);
|
|
2005
2591
|
}
|
|
2006
2592
|
}
|
|
2007
|
-
async
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
updates
|
|
2011
|
-
}) {
|
|
2012
|
-
try {
|
|
2013
|
-
await this.operations.update({
|
|
2014
|
-
tableName: storage.TABLE_AI_SPANS,
|
|
2015
|
-
keys: { spanId, traceId },
|
|
2016
|
-
data: { ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
2017
|
-
});
|
|
2018
|
-
} catch (error$1) {
|
|
2593
|
+
async listThreadsByResourceId(args) {
|
|
2594
|
+
const { resourceId, page = 0, perPage: perPageInput, orderBy } = args;
|
|
2595
|
+
if (page < 0) {
|
|
2019
2596
|
throw new error.MastraError(
|
|
2020
2597
|
{
|
|
2021
|
-
id: "
|
|
2598
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_THREADS_BY_RESOURCE_ID", "INVALID_PAGE"),
|
|
2022
2599
|
domain: error.ErrorDomain.STORAGE,
|
|
2023
2600
|
category: error.ErrorCategory.USER,
|
|
2024
|
-
details: {
|
|
2025
|
-
spanId,
|
|
2026
|
-
traceId
|
|
2027
|
-
}
|
|
2601
|
+
details: { page }
|
|
2028
2602
|
},
|
|
2029
|
-
|
|
2603
|
+
new Error("page must be >= 0")
|
|
2030
2604
|
);
|
|
2031
2605
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
pagination
|
|
2036
|
-
}) {
|
|
2037
|
-
const page = pagination?.page ?? 0;
|
|
2038
|
-
const perPage = pagination?.perPage ?? 10;
|
|
2039
|
-
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
2040
|
-
const filtersWithDateRange = {
|
|
2041
|
-
...actualFilters,
|
|
2042
|
-
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
2043
|
-
parentSpanId: null
|
|
2044
|
-
};
|
|
2045
|
-
const whereClause = prepareWhereClause(filtersWithDateRange, storage.AI_SPAN_SCHEMA);
|
|
2046
|
-
let actualWhereClause = whereClause.sql || "";
|
|
2047
|
-
if (entityId && entityType) {
|
|
2048
|
-
const statement = `name = ?`;
|
|
2049
|
-
let name = "";
|
|
2050
|
-
if (entityType === "workflow") {
|
|
2051
|
-
name = `workflow run: '${entityId}'`;
|
|
2052
|
-
} else if (entityType === "agent") {
|
|
2053
|
-
name = `agent run: '${entityId}'`;
|
|
2054
|
-
} else {
|
|
2055
|
-
const error$1 = new error.MastraError({
|
|
2056
|
-
id: "LIBSQL_STORE_GET_AI_TRACES_PAGINATED_FAILED",
|
|
2057
|
-
domain: error.ErrorDomain.STORAGE,
|
|
2058
|
-
category: error.ErrorCategory.USER,
|
|
2059
|
-
details: {
|
|
2060
|
-
entityType
|
|
2061
|
-
},
|
|
2062
|
-
text: `Cannot filter by entity type: ${entityType}`
|
|
2063
|
-
});
|
|
2064
|
-
this.logger?.trackException(error$1);
|
|
2065
|
-
throw error$1;
|
|
2066
|
-
}
|
|
2067
|
-
whereClause.args.push(name);
|
|
2068
|
-
if (actualWhereClause) {
|
|
2069
|
-
actualWhereClause += ` AND ${statement}`;
|
|
2070
|
-
} else {
|
|
2071
|
-
actualWhereClause += `WHERE ${statement}`;
|
|
2072
|
-
}
|
|
2073
|
-
}
|
|
2074
|
-
const orderBy = "startedAt DESC";
|
|
2075
|
-
let count = 0;
|
|
2606
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
2607
|
+
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
2608
|
+
const { field, direction } = this.parseOrderBy(orderBy);
|
|
2076
2609
|
try {
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2610
|
+
const baseQuery = `FROM ${storage.TABLE_THREADS} WHERE resourceId = ?`;
|
|
2611
|
+
const queryParams = [resourceId];
|
|
2612
|
+
const mapRowToStorageThreadType = (row) => ({
|
|
2613
|
+
id: row.id,
|
|
2614
|
+
resourceId: row.resourceId,
|
|
2615
|
+
title: row.title,
|
|
2616
|
+
createdAt: new Date(row.createdAt),
|
|
2617
|
+
// Convert string to Date
|
|
2618
|
+
updatedAt: new Date(row.updatedAt),
|
|
2619
|
+
// Convert string to Date
|
|
2620
|
+
metadata: typeof row.metadata === "string" ? JSON.parse(row.metadata) : row.metadata
|
|
2080
2621
|
});
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
);
|
|
2090
|
-
}
|
|
2091
|
-
if (count === 0) {
|
|
2092
|
-
return {
|
|
2093
|
-
pagination: {
|
|
2622
|
+
const countResult = await this.#client.execute({
|
|
2623
|
+
sql: `SELECT COUNT(*) as count ${baseQuery}`,
|
|
2624
|
+
args: queryParams
|
|
2625
|
+
});
|
|
2626
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
2627
|
+
if (total === 0) {
|
|
2628
|
+
return {
|
|
2629
|
+
threads: [],
|
|
2094
2630
|
total: 0,
|
|
2095
2631
|
page,
|
|
2096
|
-
perPage,
|
|
2632
|
+
perPage: perPageForResponse,
|
|
2097
2633
|
hasMore: false
|
|
2098
|
-
}
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
tableName: storage.TABLE_AI_SPANS,
|
|
2105
|
-
whereClause: {
|
|
2106
|
-
sql: actualWhereClause,
|
|
2107
|
-
args: whereClause.args
|
|
2108
|
-
},
|
|
2109
|
-
orderBy,
|
|
2110
|
-
offset: page * perPage,
|
|
2111
|
-
limit: perPage
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
2637
|
+
const dataResult = await this.#client.execute({
|
|
2638
|
+
sql: `SELECT * ${baseQuery} ORDER BY "${field}" ${direction} LIMIT ? OFFSET ?`,
|
|
2639
|
+
args: [...queryParams, limitValue, offset]
|
|
2112
2640
|
});
|
|
2641
|
+
const threads = (dataResult.rows || []).map(mapRowToStorageThreadType);
|
|
2113
2642
|
return {
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
},
|
|
2120
|
-
spans: spans.map((span) => transformFromSqlRow({ tableName: storage.TABLE_AI_SPANS, sqlRow: span }))
|
|
2643
|
+
threads,
|
|
2644
|
+
total,
|
|
2645
|
+
page,
|
|
2646
|
+
perPage: perPageForResponse,
|
|
2647
|
+
hasMore: perPageInput === false ? false : offset + perPage < total
|
|
2121
2648
|
};
|
|
2122
2649
|
} catch (error$1) {
|
|
2123
|
-
|
|
2650
|
+
const mastraError = new error.MastraError(
|
|
2124
2651
|
{
|
|
2125
|
-
id: "
|
|
2652
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_THREADS_BY_RESOURCE_ID", "FAILED"),
|
|
2126
2653
|
domain: error.ErrorDomain.STORAGE,
|
|
2127
|
-
category: error.ErrorCategory.
|
|
2654
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2655
|
+
details: { resourceId }
|
|
2128
2656
|
},
|
|
2129
2657
|
error$1
|
|
2130
2658
|
);
|
|
2659
|
+
this.logger?.trackException?.(mastraError);
|
|
2660
|
+
this.logger?.error?.(mastraError.toString());
|
|
2661
|
+
return {
|
|
2662
|
+
threads: [],
|
|
2663
|
+
total: 0,
|
|
2664
|
+
page,
|
|
2665
|
+
perPage: perPageForResponse,
|
|
2666
|
+
hasMore: false
|
|
2667
|
+
};
|
|
2131
2668
|
}
|
|
2132
2669
|
}
|
|
2133
|
-
async
|
|
2670
|
+
async saveThread({ thread }) {
|
|
2134
2671
|
try {
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
updatedAt: now
|
|
2142
|
-
}))
|
|
2672
|
+
await this.#db.insert({
|
|
2673
|
+
tableName: storage.TABLE_THREADS,
|
|
2674
|
+
record: {
|
|
2675
|
+
...thread,
|
|
2676
|
+
metadata: JSON.stringify(thread.metadata)
|
|
2677
|
+
}
|
|
2143
2678
|
});
|
|
2679
|
+
return thread;
|
|
2144
2680
|
} catch (error$1) {
|
|
2145
|
-
|
|
2681
|
+
const mastraError = new error.MastraError(
|
|
2146
2682
|
{
|
|
2147
|
-
id: "
|
|
2683
|
+
id: storage.createStorageErrorId("LIBSQL", "SAVE_THREAD", "FAILED"),
|
|
2148
2684
|
domain: error.ErrorDomain.STORAGE,
|
|
2149
|
-
category: error.ErrorCategory.
|
|
2685
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2686
|
+
details: { threadId: thread.id }
|
|
2150
2687
|
},
|
|
2151
2688
|
error$1
|
|
2152
2689
|
);
|
|
2690
|
+
this.logger?.trackException?.(mastraError);
|
|
2691
|
+
this.logger?.error?.(mastraError.toString());
|
|
2692
|
+
throw mastraError;
|
|
2153
2693
|
}
|
|
2154
2694
|
}
|
|
2155
|
-
async
|
|
2695
|
+
async updateThread({
|
|
2696
|
+
id,
|
|
2697
|
+
title,
|
|
2698
|
+
metadata
|
|
2699
|
+
}) {
|
|
2700
|
+
const thread = await this.getThreadById({ threadId: id });
|
|
2701
|
+
if (!thread) {
|
|
2702
|
+
throw new error.MastraError({
|
|
2703
|
+
id: storage.createStorageErrorId("LIBSQL", "UPDATE_THREAD", "NOT_FOUND"),
|
|
2704
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2705
|
+
category: error.ErrorCategory.USER,
|
|
2706
|
+
text: `Thread ${id} not found`,
|
|
2707
|
+
details: {
|
|
2708
|
+
status: 404,
|
|
2709
|
+
threadId: id
|
|
2710
|
+
}
|
|
2711
|
+
});
|
|
2712
|
+
}
|
|
2713
|
+
const updatedThread = {
|
|
2714
|
+
...thread,
|
|
2715
|
+
title,
|
|
2716
|
+
metadata: {
|
|
2717
|
+
...thread.metadata,
|
|
2718
|
+
...metadata
|
|
2719
|
+
}
|
|
2720
|
+
};
|
|
2156
2721
|
try {
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
keys: { spanId: record.spanId, traceId: record.traceId },
|
|
2161
|
-
data: { ...record.updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
2162
|
-
}))
|
|
2722
|
+
await this.#client.execute({
|
|
2723
|
+
sql: `UPDATE ${storage.TABLE_THREADS} SET title = ?, metadata = ? WHERE id = ?`,
|
|
2724
|
+
args: [title, JSON.stringify(updatedThread.metadata), id]
|
|
2163
2725
|
});
|
|
2726
|
+
return updatedThread;
|
|
2164
2727
|
} catch (error$1) {
|
|
2165
2728
|
throw new error.MastraError(
|
|
2166
2729
|
{
|
|
2167
|
-
id: "
|
|
2730
|
+
id: storage.createStorageErrorId("LIBSQL", "UPDATE_THREAD", "FAILED"),
|
|
2168
2731
|
domain: error.ErrorDomain.STORAGE,
|
|
2169
|
-
category: error.ErrorCategory.
|
|
2732
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2733
|
+
text: `Failed to update thread ${id}`,
|
|
2734
|
+
details: { threadId: id }
|
|
2170
2735
|
},
|
|
2171
2736
|
error$1
|
|
2172
2737
|
);
|
|
2173
2738
|
}
|
|
2174
2739
|
}
|
|
2175
|
-
async
|
|
2740
|
+
async deleteThread({ threadId }) {
|
|
2176
2741
|
try {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2742
|
+
await this.#client.execute({
|
|
2743
|
+
sql: `DELETE FROM ${storage.TABLE_MESSAGES} WHERE thread_id = ?`,
|
|
2744
|
+
args: [threadId]
|
|
2745
|
+
});
|
|
2746
|
+
await this.#client.execute({
|
|
2747
|
+
sql: `DELETE FROM ${storage.TABLE_THREADS} WHERE id = ?`,
|
|
2748
|
+
args: [threadId]
|
|
2181
2749
|
});
|
|
2182
2750
|
} catch (error$1) {
|
|
2183
2751
|
throw new error.MastraError(
|
|
2184
2752
|
{
|
|
2185
|
-
id: "
|
|
2753
|
+
id: storage.createStorageErrorId("LIBSQL", "DELETE_THREAD", "FAILED"),
|
|
2186
2754
|
domain: error.ErrorDomain.STORAGE,
|
|
2187
|
-
category: error.ErrorCategory.
|
|
2755
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
2756
|
+
details: { threadId }
|
|
2188
2757
|
},
|
|
2189
2758
|
error$1
|
|
2190
2759
|
);
|
|
2191
2760
|
}
|
|
2192
2761
|
}
|
|
2193
2762
|
};
|
|
2194
|
-
var
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
* Maximum number of retries for write operations if an SQLITE_BUSY error occurs.
|
|
2198
|
-
* @default 5
|
|
2199
|
-
*/
|
|
2200
|
-
maxRetries;
|
|
2201
|
-
/**
|
|
2202
|
-
* Initial backoff time in milliseconds for retrying write operations on SQLITE_BUSY.
|
|
2203
|
-
* The backoff time will double with each retry (exponential backoff).
|
|
2204
|
-
* @default 100
|
|
2205
|
-
*/
|
|
2206
|
-
initialBackoffMs;
|
|
2207
|
-
constructor({
|
|
2208
|
-
client,
|
|
2209
|
-
maxRetries,
|
|
2210
|
-
initialBackoffMs
|
|
2211
|
-
}) {
|
|
2763
|
+
var ObservabilityLibSQL = class extends storage.ObservabilityStorage {
|
|
2764
|
+
#db;
|
|
2765
|
+
constructor(config) {
|
|
2212
2766
|
super();
|
|
2213
|
-
|
|
2214
|
-
this
|
|
2215
|
-
this.initialBackoffMs = initialBackoffMs ?? 100;
|
|
2216
|
-
}
|
|
2217
|
-
async hasColumn(table, column) {
|
|
2218
|
-
const result = await this.client.execute({
|
|
2219
|
-
sql: `PRAGMA table_info(${table})`
|
|
2220
|
-
});
|
|
2221
|
-
return (await result.rows)?.some((row) => row.name === column);
|
|
2767
|
+
const client = resolveClient(config);
|
|
2768
|
+
this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
|
|
2222
2769
|
}
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
const columns = Object.entries(schema).map(([name, col]) => {
|
|
2226
|
-
const parsedColumnName = utils.parseSqlIdentifier(name, "column name");
|
|
2227
|
-
let type = col.type.toUpperCase();
|
|
2228
|
-
if (type === "TEXT") type = "TEXT";
|
|
2229
|
-
if (type === "TIMESTAMP") type = "TEXT";
|
|
2230
|
-
const nullable = col.nullable ? "" : "NOT NULL";
|
|
2231
|
-
const primaryKey = col.primaryKey ? "PRIMARY KEY" : "";
|
|
2232
|
-
return `${parsedColumnName} ${type} ${nullable} ${primaryKey}`.trim();
|
|
2233
|
-
});
|
|
2234
|
-
if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
|
|
2235
|
-
const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
2236
|
-
${columns.join(",\n")},
|
|
2237
|
-
PRIMARY KEY (workflow_name, run_id)
|
|
2238
|
-
)`;
|
|
2239
|
-
return stmnt;
|
|
2240
|
-
}
|
|
2241
|
-
if (tableName === storage.TABLE_AI_SPANS) {
|
|
2242
|
-
const stmnt = `CREATE TABLE IF NOT EXISTS ${parsedTableName} (
|
|
2243
|
-
${columns.join(",\n")},
|
|
2244
|
-
PRIMARY KEY (traceId, spanId)
|
|
2245
|
-
)`;
|
|
2246
|
-
return stmnt;
|
|
2247
|
-
}
|
|
2248
|
-
return `CREATE TABLE IF NOT EXISTS ${parsedTableName} (${columns.join(", ")})`;
|
|
2770
|
+
async init() {
|
|
2771
|
+
await this.#db.createTable({ tableName: storage.TABLE_SPANS, schema: storage.SPAN_SCHEMA });
|
|
2249
2772
|
}
|
|
2250
|
-
async
|
|
2251
|
-
tableName
|
|
2252
|
-
|
|
2253
|
-
|
|
2773
|
+
async dangerouslyClearAll() {
|
|
2774
|
+
await this.#db.deleteData({ tableName: storage.TABLE_SPANS });
|
|
2775
|
+
}
|
|
2776
|
+
async createSpan(span) {
|
|
2254
2777
|
try {
|
|
2255
|
-
|
|
2256
|
-
const
|
|
2257
|
-
|
|
2778
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2779
|
+
const record = {
|
|
2780
|
+
...span,
|
|
2781
|
+
createdAt: now,
|
|
2782
|
+
updatedAt: now
|
|
2783
|
+
};
|
|
2784
|
+
return this.#db.insert({ tableName: storage.TABLE_SPANS, record });
|
|
2258
2785
|
} catch (error$1) {
|
|
2259
2786
|
throw new error.MastraError(
|
|
2260
2787
|
{
|
|
2261
|
-
id: "
|
|
2788
|
+
id: storage.createStorageErrorId("LIBSQL", "CREATE_SPAN", "FAILED"),
|
|
2262
2789
|
domain: error.ErrorDomain.STORAGE,
|
|
2263
|
-
category: error.ErrorCategory.
|
|
2790
|
+
category: error.ErrorCategory.USER,
|
|
2264
2791
|
details: {
|
|
2265
|
-
|
|
2792
|
+
spanId: span.spanId,
|
|
2793
|
+
traceId: span.traceId,
|
|
2794
|
+
spanType: span.spanType,
|
|
2795
|
+
spanName: span.name
|
|
2266
2796
|
}
|
|
2267
2797
|
},
|
|
2268
2798
|
error$1
|
|
2269
2799
|
);
|
|
2270
2800
|
}
|
|
2271
2801
|
}
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
}) {
|
|
2288
|
-
await this.client.execute(
|
|
2289
|
-
prepareStatement({
|
|
2290
|
-
tableName,
|
|
2291
|
-
record
|
|
2292
|
-
})
|
|
2293
|
-
);
|
|
2294
|
-
}
|
|
2295
|
-
insert(args) {
|
|
2296
|
-
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
2297
|
-
logger: this.logger,
|
|
2298
|
-
maxRetries: this.maxRetries,
|
|
2299
|
-
initialBackoffMs: this.initialBackoffMs
|
|
2300
|
-
});
|
|
2301
|
-
return executeWriteOperationWithRetry(() => this.doInsert(args), `insert into table ${args.tableName}`);
|
|
2302
|
-
}
|
|
2303
|
-
async load({ tableName, keys }) {
|
|
2304
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
2305
|
-
const parsedKeys = Object.keys(keys).map((key) => utils.parseSqlIdentifier(key, "column name"));
|
|
2306
|
-
const conditions = parsedKeys.map((key) => `${key} = ?`).join(" AND ");
|
|
2307
|
-
const values = Object.values(keys);
|
|
2308
|
-
const result = await this.client.execute({
|
|
2309
|
-
sql: `SELECT * FROM ${parsedTableName} WHERE ${conditions} ORDER BY createdAt DESC LIMIT 1`,
|
|
2310
|
-
args: values
|
|
2311
|
-
});
|
|
2312
|
-
if (!result.rows || result.rows.length === 0) {
|
|
2313
|
-
return null;
|
|
2314
|
-
}
|
|
2315
|
-
const row = result.rows[0];
|
|
2316
|
-
const parsed = Object.fromEntries(
|
|
2317
|
-
Object.entries(row || {}).map(([k, v]) => {
|
|
2318
|
-
try {
|
|
2319
|
-
return [k, typeof v === "string" ? v.startsWith("{") || v.startsWith("[") ? JSON.parse(v) : v : v];
|
|
2320
|
-
} catch {
|
|
2321
|
-
return [k, v];
|
|
2322
|
-
}
|
|
2323
|
-
})
|
|
2324
|
-
);
|
|
2325
|
-
return parsed;
|
|
2326
|
-
}
|
|
2327
|
-
async loadMany({
|
|
2328
|
-
tableName,
|
|
2329
|
-
whereClause,
|
|
2330
|
-
orderBy,
|
|
2331
|
-
offset,
|
|
2332
|
-
limit,
|
|
2333
|
-
args
|
|
2334
|
-
}) {
|
|
2335
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
2336
|
-
let statement = `SELECT * FROM ${parsedTableName}`;
|
|
2337
|
-
if (whereClause?.sql) {
|
|
2338
|
-
statement += `${whereClause.sql}`;
|
|
2339
|
-
}
|
|
2340
|
-
if (orderBy) {
|
|
2341
|
-
statement += ` ORDER BY ${orderBy}`;
|
|
2342
|
-
}
|
|
2343
|
-
if (limit) {
|
|
2344
|
-
statement += ` LIMIT ${limit}`;
|
|
2345
|
-
}
|
|
2346
|
-
if (offset) {
|
|
2347
|
-
statement += ` OFFSET ${offset}`;
|
|
2348
|
-
}
|
|
2349
|
-
const result = await this.client.execute({
|
|
2350
|
-
sql: statement,
|
|
2351
|
-
args: [...whereClause?.args ?? [], ...args ?? []]
|
|
2352
|
-
});
|
|
2353
|
-
return result.rows;
|
|
2354
|
-
}
|
|
2355
|
-
async loadTotalCount({
|
|
2356
|
-
tableName,
|
|
2357
|
-
whereClause
|
|
2358
|
-
}) {
|
|
2359
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
2360
|
-
const statement = `SELECT COUNT(*) as count FROM ${parsedTableName} ${whereClause ? `${whereClause.sql}` : ""}`;
|
|
2361
|
-
const result = await this.client.execute({
|
|
2362
|
-
sql: statement,
|
|
2363
|
-
args: whereClause?.args ?? []
|
|
2364
|
-
});
|
|
2365
|
-
if (!result.rows || result.rows.length === 0) {
|
|
2366
|
-
return 0;
|
|
2367
|
-
}
|
|
2368
|
-
return result.rows[0]?.count ?? 0;
|
|
2369
|
-
}
|
|
2370
|
-
update(args) {
|
|
2371
|
-
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
2372
|
-
logger: this.logger,
|
|
2373
|
-
maxRetries: this.maxRetries,
|
|
2374
|
-
initialBackoffMs: this.initialBackoffMs
|
|
2375
|
-
});
|
|
2376
|
-
return executeWriteOperationWithRetry(() => this.executeUpdate(args), `update table ${args.tableName}`);
|
|
2377
|
-
}
|
|
2378
|
-
async executeUpdate({
|
|
2379
|
-
tableName,
|
|
2380
|
-
keys,
|
|
2381
|
-
data
|
|
2382
|
-
}) {
|
|
2383
|
-
await this.client.execute(prepareUpdateStatement({ tableName, updates: data, keys }));
|
|
2384
|
-
}
|
|
2385
|
-
async doBatchInsert({
|
|
2386
|
-
tableName,
|
|
2387
|
-
records
|
|
2388
|
-
}) {
|
|
2389
|
-
if (records.length === 0) return;
|
|
2390
|
-
const batchStatements = records.map((r) => prepareStatement({ tableName, record: r }));
|
|
2391
|
-
await this.client.batch(batchStatements, "write");
|
|
2392
|
-
}
|
|
2393
|
-
batchInsert(args) {
|
|
2394
|
-
const executeWriteOperationWithRetry = createExecuteWriteOperationWithRetry({
|
|
2395
|
-
logger: this.logger,
|
|
2396
|
-
maxRetries: this.maxRetries,
|
|
2397
|
-
initialBackoffMs: this.initialBackoffMs
|
|
2398
|
-
});
|
|
2399
|
-
return executeWriteOperationWithRetry(
|
|
2400
|
-
() => this.doBatchInsert(args),
|
|
2401
|
-
`batch insert into table ${args.tableName}`
|
|
2402
|
-
).catch((error$1) => {
|
|
2802
|
+
async getTrace(traceId) {
|
|
2803
|
+
try {
|
|
2804
|
+
const spans = await this.#db.selectMany({
|
|
2805
|
+
tableName: storage.TABLE_SPANS,
|
|
2806
|
+
whereClause: { sql: " WHERE traceId = ?", args: [traceId] },
|
|
2807
|
+
orderBy: "startedAt DESC"
|
|
2808
|
+
});
|
|
2809
|
+
if (!spans || spans.length === 0) {
|
|
2810
|
+
return null;
|
|
2811
|
+
}
|
|
2812
|
+
return {
|
|
2813
|
+
traceId,
|
|
2814
|
+
spans: spans.map((span) => transformFromSqlRow({ tableName: storage.TABLE_SPANS, sqlRow: span }))
|
|
2815
|
+
};
|
|
2816
|
+
} catch (error$1) {
|
|
2403
2817
|
throw new error.MastraError(
|
|
2404
2818
|
{
|
|
2405
|
-
id: "
|
|
2819
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_TRACE", "FAILED"),
|
|
2406
2820
|
domain: error.ErrorDomain.STORAGE,
|
|
2407
|
-
category: error.ErrorCategory.
|
|
2821
|
+
category: error.ErrorCategory.USER,
|
|
2408
2822
|
details: {
|
|
2409
|
-
|
|
2823
|
+
traceId
|
|
2410
2824
|
}
|
|
2411
2825
|
},
|
|
2412
2826
|
error$1
|
|
2413
2827
|
);
|
|
2414
|
-
}
|
|
2828
|
+
}
|
|
2415
2829
|
}
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
).catch((error$1) => {
|
|
2830
|
+
async updateSpan({
|
|
2831
|
+
spanId,
|
|
2832
|
+
traceId,
|
|
2833
|
+
updates
|
|
2834
|
+
}) {
|
|
2835
|
+
try {
|
|
2836
|
+
await this.#db.update({
|
|
2837
|
+
tableName: storage.TABLE_SPANS,
|
|
2838
|
+
keys: { spanId, traceId },
|
|
2839
|
+
data: { ...updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
2840
|
+
});
|
|
2841
|
+
} catch (error$1) {
|
|
2429
2842
|
throw new error.MastraError(
|
|
2430
2843
|
{
|
|
2431
|
-
id: "
|
|
2844
|
+
id: storage.createStorageErrorId("LIBSQL", "UPDATE_SPAN", "FAILED"),
|
|
2432
2845
|
domain: error.ErrorDomain.STORAGE,
|
|
2433
|
-
category: error.ErrorCategory.
|
|
2846
|
+
category: error.ErrorCategory.USER,
|
|
2434
2847
|
details: {
|
|
2435
|
-
|
|
2848
|
+
spanId,
|
|
2849
|
+
traceId
|
|
2436
2850
|
}
|
|
2437
2851
|
},
|
|
2438
2852
|
error$1
|
|
2439
2853
|
);
|
|
2440
|
-
}
|
|
2854
|
+
}
|
|
2441
2855
|
}
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
async executeBatchUpdate({
|
|
2446
|
-
tableName,
|
|
2447
|
-
updates
|
|
2856
|
+
async getTracesPaginated({
|
|
2857
|
+
filters,
|
|
2858
|
+
pagination
|
|
2448
2859
|
}) {
|
|
2449
|
-
|
|
2450
|
-
const
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2860
|
+
const page = pagination?.page ?? 0;
|
|
2861
|
+
const perPage = pagination?.perPage ?? 10;
|
|
2862
|
+
const { entityId, entityType, ...actualFilters } = filters || {};
|
|
2863
|
+
const filtersWithDateRange = {
|
|
2864
|
+
...actualFilters,
|
|
2865
|
+
...buildDateRangeFilter(pagination?.dateRange, "startedAt"),
|
|
2866
|
+
parentSpanId: null
|
|
2867
|
+
};
|
|
2868
|
+
const whereClause = prepareWhereClause(filtersWithDateRange, storage.SPAN_SCHEMA);
|
|
2869
|
+
let actualWhereClause = whereClause.sql || "";
|
|
2870
|
+
if (entityId && entityType) {
|
|
2871
|
+
const statement = `name = ?`;
|
|
2872
|
+
let name = "";
|
|
2873
|
+
if (entityType === "workflow") {
|
|
2874
|
+
name = `workflow run: '${entityId}'`;
|
|
2875
|
+
} else if (entityType === "agent") {
|
|
2876
|
+
name = `agent run: '${entityId}'`;
|
|
2877
|
+
} else {
|
|
2878
|
+
const error$1 = new error.MastraError({
|
|
2879
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_TRACES_PAGINATED", "INVALID_ENTITY_TYPE"),
|
|
2880
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2881
|
+
category: error.ErrorCategory.USER,
|
|
2882
|
+
details: {
|
|
2883
|
+
entityType
|
|
2884
|
+
},
|
|
2885
|
+
text: `Cannot filter by entity type: ${entityType}`
|
|
2886
|
+
});
|
|
2887
|
+
this.logger?.trackException(error$1);
|
|
2888
|
+
throw error$1;
|
|
2889
|
+
}
|
|
2890
|
+
whereClause.args.push(name);
|
|
2891
|
+
if (actualWhereClause) {
|
|
2892
|
+
actualWhereClause += ` AND ${statement}`;
|
|
2893
|
+
} else {
|
|
2894
|
+
actualWhereClause += `WHERE ${statement}`;
|
|
2895
|
+
}
|
|
2896
|
+
}
|
|
2897
|
+
const orderBy = "startedAt DESC";
|
|
2898
|
+
let count = 0;
|
|
2899
|
+
try {
|
|
2900
|
+
count = await this.#db.selectTotalCount({
|
|
2901
|
+
tableName: storage.TABLE_SPANS,
|
|
2902
|
+
whereClause: { sql: actualWhereClause, args: whereClause.args }
|
|
2903
|
+
});
|
|
2904
|
+
} catch (error$1) {
|
|
2905
|
+
throw new error.MastraError(
|
|
2906
|
+
{
|
|
2907
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_TRACES_PAGINATED", "COUNT_FAILED"),
|
|
2908
|
+
domain: error.ErrorDomain.STORAGE,
|
|
2909
|
+
category: error.ErrorCategory.USER
|
|
2910
|
+
},
|
|
2911
|
+
error$1
|
|
2912
|
+
);
|
|
2913
|
+
}
|
|
2914
|
+
if (count === 0) {
|
|
2915
|
+
return {
|
|
2916
|
+
pagination: {
|
|
2917
|
+
total: 0,
|
|
2918
|
+
page,
|
|
2919
|
+
perPage,
|
|
2920
|
+
hasMore: false
|
|
2921
|
+
},
|
|
2922
|
+
spans: []
|
|
2923
|
+
};
|
|
2924
|
+
}
|
|
2925
|
+
try {
|
|
2926
|
+
const spans = await this.#db.selectMany({
|
|
2927
|
+
tableName: storage.TABLE_SPANS,
|
|
2928
|
+
whereClause: {
|
|
2929
|
+
sql: actualWhereClause,
|
|
2930
|
+
args: whereClause.args
|
|
2931
|
+
},
|
|
2932
|
+
orderBy,
|
|
2933
|
+
offset: page * perPage,
|
|
2934
|
+
limit: perPage
|
|
2935
|
+
});
|
|
2936
|
+
return {
|
|
2937
|
+
pagination: {
|
|
2938
|
+
total: count,
|
|
2939
|
+
page,
|
|
2940
|
+
perPage,
|
|
2941
|
+
hasMore: spans.length === perPage
|
|
2942
|
+
},
|
|
2943
|
+
spans: spans.map((span) => transformFromSqlRow({ tableName: storage.TABLE_SPANS, sqlRow: span }))
|
|
2944
|
+
};
|
|
2945
|
+
} catch (error$1) {
|
|
2472
2946
|
throw new error.MastraError(
|
|
2473
2947
|
{
|
|
2474
|
-
id: "
|
|
2948
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_TRACES_PAGINATED", "FAILED"),
|
|
2475
2949
|
domain: error.ErrorDomain.STORAGE,
|
|
2476
|
-
category: error.ErrorCategory.
|
|
2477
|
-
details: {
|
|
2478
|
-
tableName
|
|
2479
|
-
}
|
|
2950
|
+
category: error.ErrorCategory.USER
|
|
2480
2951
|
},
|
|
2481
2952
|
error$1
|
|
2482
2953
|
);
|
|
2483
|
-
}
|
|
2484
|
-
}
|
|
2485
|
-
/**
|
|
2486
|
-
* Deletes multiple records in batch. Each record can be deleted based on single or composite keys.
|
|
2487
|
-
*/
|
|
2488
|
-
async executeBatchDelete({
|
|
2489
|
-
tableName,
|
|
2490
|
-
keys
|
|
2491
|
-
}) {
|
|
2492
|
-
if (keys.length === 0) return;
|
|
2493
|
-
const batchStatements = keys.map(
|
|
2494
|
-
(keyObj) => prepareDeleteStatement({
|
|
2495
|
-
tableName,
|
|
2496
|
-
keys: keyObj
|
|
2497
|
-
})
|
|
2498
|
-
);
|
|
2499
|
-
await this.client.batch(batchStatements, "write");
|
|
2954
|
+
}
|
|
2500
2955
|
}
|
|
2501
|
-
|
|
2502
|
-
* Alters table schema to add columns if they don't exist
|
|
2503
|
-
* @param tableName Name of the table
|
|
2504
|
-
* @param schema Schema of the table
|
|
2505
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
2506
|
-
*/
|
|
2507
|
-
async alterTable({
|
|
2508
|
-
tableName,
|
|
2509
|
-
schema,
|
|
2510
|
-
ifNotExists
|
|
2511
|
-
}) {
|
|
2512
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
2956
|
+
async batchCreateSpans(args) {
|
|
2513
2957
|
try {
|
|
2514
|
-
const
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
const alterSql = `ALTER TABLE ${parsedTableName} ADD COLUMN "${columnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
|
|
2524
|
-
await this.client.execute(alterSql);
|
|
2525
|
-
this.logger?.debug?.(`Added column ${columnName} to table ${parsedTableName}`);
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2958
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
2959
|
+
return this.#db.batchInsert({
|
|
2960
|
+
tableName: storage.TABLE_SPANS,
|
|
2961
|
+
records: args.records.map((record) => ({
|
|
2962
|
+
...record,
|
|
2963
|
+
createdAt: now,
|
|
2964
|
+
updatedAt: now
|
|
2965
|
+
}))
|
|
2966
|
+
});
|
|
2528
2967
|
} catch (error$1) {
|
|
2529
2968
|
throw new error.MastraError(
|
|
2530
2969
|
{
|
|
2531
|
-
id: "
|
|
2970
|
+
id: storage.createStorageErrorId("LIBSQL", "BATCH_CREATE_SPANS", "FAILED"),
|
|
2532
2971
|
domain: error.ErrorDomain.STORAGE,
|
|
2533
|
-
category: error.ErrorCategory.
|
|
2534
|
-
details: {
|
|
2535
|
-
tableName
|
|
2536
|
-
}
|
|
2972
|
+
category: error.ErrorCategory.USER
|
|
2537
2973
|
},
|
|
2538
2974
|
error$1
|
|
2539
2975
|
);
|
|
2540
2976
|
}
|
|
2541
2977
|
}
|
|
2542
|
-
async
|
|
2543
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
2978
|
+
async batchUpdateSpans(args) {
|
|
2544
2979
|
try {
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2980
|
+
return this.#db.batchUpdate({
|
|
2981
|
+
tableName: storage.TABLE_SPANS,
|
|
2982
|
+
updates: args.records.map((record) => ({
|
|
2983
|
+
keys: { spanId: record.spanId, traceId: record.traceId },
|
|
2984
|
+
data: { ...record.updates, updatedAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
2985
|
+
}))
|
|
2986
|
+
});
|
|
2987
|
+
} catch (error$1) {
|
|
2988
|
+
throw new error.MastraError(
|
|
2548
2989
|
{
|
|
2549
|
-
id: "
|
|
2990
|
+
id: storage.createStorageErrorId("LIBSQL", "BATCH_UPDATE_SPANS", "FAILED"),
|
|
2550
2991
|
domain: error.ErrorDomain.STORAGE,
|
|
2551
|
-
category: error.ErrorCategory.
|
|
2552
|
-
details: {
|
|
2553
|
-
tableName
|
|
2554
|
-
}
|
|
2992
|
+
category: error.ErrorCategory.USER
|
|
2555
2993
|
},
|
|
2556
|
-
|
|
2994
|
+
error$1
|
|
2557
2995
|
);
|
|
2558
|
-
this.logger?.trackException?.(mastraError);
|
|
2559
|
-
this.logger?.error?.(mastraError.toString());
|
|
2560
2996
|
}
|
|
2561
2997
|
}
|
|
2562
|
-
async
|
|
2563
|
-
const parsedTableName = utils.parseSqlIdentifier(tableName, "table name");
|
|
2998
|
+
async batchDeleteTraces(args) {
|
|
2564
2999
|
try {
|
|
2565
|
-
|
|
2566
|
-
|
|
3000
|
+
const keys = args.traceIds.map((traceId) => ({ traceId }));
|
|
3001
|
+
return this.#db.batchDelete({
|
|
3002
|
+
tableName: storage.TABLE_SPANS,
|
|
3003
|
+
keys
|
|
3004
|
+
});
|
|
3005
|
+
} catch (error$1) {
|
|
2567
3006
|
throw new error.MastraError(
|
|
2568
3007
|
{
|
|
2569
|
-
id: "
|
|
3008
|
+
id: storage.createStorageErrorId("LIBSQL", "BATCH_DELETE_TRACES", "FAILED"),
|
|
2570
3009
|
domain: error.ErrorDomain.STORAGE,
|
|
2571
|
-
category: error.ErrorCategory.
|
|
2572
|
-
details: {
|
|
2573
|
-
tableName
|
|
2574
|
-
}
|
|
3010
|
+
category: error.ErrorCategory.USER
|
|
2575
3011
|
},
|
|
2576
|
-
|
|
3012
|
+
error$1
|
|
2577
3013
|
);
|
|
2578
3014
|
}
|
|
2579
3015
|
}
|
|
2580
3016
|
};
|
|
2581
3017
|
var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
2582
|
-
|
|
2583
|
-
client;
|
|
2584
|
-
constructor(
|
|
3018
|
+
#db;
|
|
3019
|
+
#client;
|
|
3020
|
+
constructor(config) {
|
|
2585
3021
|
super();
|
|
2586
|
-
|
|
2587
|
-
this
|
|
3022
|
+
const client = resolveClient(config);
|
|
3023
|
+
this.#client = client;
|
|
3024
|
+
this.#db = new LibSQLDB({ client, maxRetries: config.maxRetries, initialBackoffMs: config.initialBackoffMs });
|
|
3025
|
+
}
|
|
3026
|
+
async init() {
|
|
3027
|
+
await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.SCORERS_SCHEMA });
|
|
3028
|
+
await this.#db.alterTable({
|
|
3029
|
+
tableName: storage.TABLE_SCORERS,
|
|
3030
|
+
schema: storage.SCORERS_SCHEMA,
|
|
3031
|
+
ifNotExists: ["spanId", "requestContext"]
|
|
3032
|
+
});
|
|
3033
|
+
}
|
|
3034
|
+
async dangerouslyClearAll() {
|
|
3035
|
+
await this.#db.deleteData({ tableName: storage.TABLE_SCORERS });
|
|
2588
3036
|
}
|
|
2589
|
-
async
|
|
3037
|
+
async listScoresByRunId({
|
|
2590
3038
|
runId,
|
|
2591
3039
|
pagination
|
|
2592
3040
|
}) {
|
|
2593
3041
|
try {
|
|
2594
|
-
const
|
|
3042
|
+
const { page, perPage: perPageInput } = pagination;
|
|
3043
|
+
const countResult = await this.#client.execute({
|
|
3044
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_SCORERS} WHERE runId = ?`,
|
|
3045
|
+
args: [runId]
|
|
3046
|
+
});
|
|
3047
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
3048
|
+
if (total === 0) {
|
|
3049
|
+
return {
|
|
3050
|
+
pagination: {
|
|
3051
|
+
total: 0,
|
|
3052
|
+
page,
|
|
3053
|
+
perPage: perPageInput,
|
|
3054
|
+
hasMore: false
|
|
3055
|
+
},
|
|
3056
|
+
scores: []
|
|
3057
|
+
};
|
|
3058
|
+
}
|
|
3059
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3060
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3061
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3062
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
3063
|
+
const result = await this.#client.execute({
|
|
2595
3064
|
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE runId = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2596
|
-
args: [runId,
|
|
3065
|
+
args: [runId, limitValue, start]
|
|
2597
3066
|
});
|
|
3067
|
+
const scores = result.rows?.map((row) => this.transformScoreRow(row)) ?? [];
|
|
2598
3068
|
return {
|
|
2599
|
-
scores
|
|
3069
|
+
scores,
|
|
2600
3070
|
pagination: {
|
|
2601
|
-
total
|
|
2602
|
-
page
|
|
2603
|
-
perPage:
|
|
2604
|
-
hasMore:
|
|
3071
|
+
total,
|
|
3072
|
+
page,
|
|
3073
|
+
perPage: perPageForResponse,
|
|
3074
|
+
hasMore: end < total
|
|
2605
3075
|
}
|
|
2606
3076
|
};
|
|
2607
3077
|
} catch (error$1) {
|
|
2608
3078
|
throw new error.MastraError(
|
|
2609
3079
|
{
|
|
2610
|
-
id: "
|
|
3080
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_SCORES_BY_RUN_ID", "FAILED"),
|
|
2611
3081
|
domain: error.ErrorDomain.STORAGE,
|
|
2612
3082
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2613
3083
|
},
|
|
@@ -2615,7 +3085,7 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2615
3085
|
);
|
|
2616
3086
|
}
|
|
2617
3087
|
}
|
|
2618
|
-
async
|
|
3088
|
+
async listScoresByScorerId({
|
|
2619
3089
|
scorerId,
|
|
2620
3090
|
entityId,
|
|
2621
3091
|
entityType,
|
|
@@ -2623,6 +3093,7 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2623
3093
|
pagination
|
|
2624
3094
|
}) {
|
|
2625
3095
|
try {
|
|
3096
|
+
const { page, perPage: perPageInput } = pagination;
|
|
2626
3097
|
const conditions = [];
|
|
2627
3098
|
const queryParams = [];
|
|
2628
3099
|
if (scorerId) {
|
|
@@ -2642,23 +3113,44 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2642
3113
|
queryParams.push(source);
|
|
2643
3114
|
}
|
|
2644
3115
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2645
|
-
const
|
|
3116
|
+
const countResult = await this.#client.execute({
|
|
3117
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_SCORERS} ${whereClause}`,
|
|
3118
|
+
args: queryParams
|
|
3119
|
+
});
|
|
3120
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
3121
|
+
if (total === 0) {
|
|
3122
|
+
return {
|
|
3123
|
+
pagination: {
|
|
3124
|
+
total: 0,
|
|
3125
|
+
page,
|
|
3126
|
+
perPage: perPageInput,
|
|
3127
|
+
hasMore: false
|
|
3128
|
+
},
|
|
3129
|
+
scores: []
|
|
3130
|
+
};
|
|
3131
|
+
}
|
|
3132
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3133
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3134
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3135
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
3136
|
+
const result = await this.#client.execute({
|
|
2646
3137
|
sql: `SELECT * FROM ${storage.TABLE_SCORERS} ${whereClause} ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2647
|
-
args: [...queryParams,
|
|
3138
|
+
args: [...queryParams, limitValue, start]
|
|
2648
3139
|
});
|
|
3140
|
+
const scores = result.rows?.map((row) => this.transformScoreRow(row)) ?? [];
|
|
2649
3141
|
return {
|
|
2650
|
-
scores
|
|
3142
|
+
scores,
|
|
2651
3143
|
pagination: {
|
|
2652
|
-
total
|
|
2653
|
-
page
|
|
2654
|
-
perPage:
|
|
2655
|
-
hasMore:
|
|
3144
|
+
total,
|
|
3145
|
+
page,
|
|
3146
|
+
perPage: perPageForResponse,
|
|
3147
|
+
hasMore: end < total
|
|
2656
3148
|
}
|
|
2657
3149
|
};
|
|
2658
3150
|
} catch (error$1) {
|
|
2659
3151
|
throw new error.MastraError(
|
|
2660
3152
|
{
|
|
2661
|
-
id: "
|
|
3153
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
|
|
2662
3154
|
domain: error.ErrorDomain.STORAGE,
|
|
2663
3155
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2664
3156
|
},
|
|
@@ -2666,48 +3158,17 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2666
3158
|
);
|
|
2667
3159
|
}
|
|
2668
3160
|
}
|
|
3161
|
+
/**
|
|
3162
|
+
* LibSQL-specific score row transformation.
|
|
3163
|
+
* Maps additionalLLMContext column to additionalContext field.
|
|
3164
|
+
*/
|
|
2669
3165
|
transformScoreRow(row) {
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
const additionalLLMContextValue = row.additionalLLMContext ? storage.safelyParseJSON(row.additionalLLMContext) : null;
|
|
2674
|
-
const runtimeContextValue = row.runtimeContext ? storage.safelyParseJSON(row.runtimeContext) : null;
|
|
2675
|
-
const metadataValue = row.metadata ? storage.safelyParseJSON(row.metadata) : null;
|
|
2676
|
-
const entityValue = row.entity ? storage.safelyParseJSON(row.entity) : null;
|
|
2677
|
-
const preprocessStepResultValue = row.preprocessStepResult ? storage.safelyParseJSON(row.preprocessStepResult) : null;
|
|
2678
|
-
const analyzeStepResultValue = row.analyzeStepResult ? storage.safelyParseJSON(row.analyzeStepResult) : null;
|
|
2679
|
-
return {
|
|
2680
|
-
id: row.id,
|
|
2681
|
-
traceId: row.traceId,
|
|
2682
|
-
spanId: row.spanId,
|
|
2683
|
-
runId: row.runId,
|
|
2684
|
-
scorer: scorerValue,
|
|
2685
|
-
score: row.score,
|
|
2686
|
-
reason: row.reason,
|
|
2687
|
-
preprocessStepResult: preprocessStepResultValue,
|
|
2688
|
-
analyzeStepResult: analyzeStepResultValue,
|
|
2689
|
-
analyzePrompt: row.analyzePrompt,
|
|
2690
|
-
preprocessPrompt: row.preprocessPrompt,
|
|
2691
|
-
generateScorePrompt: row.generateScorePrompt,
|
|
2692
|
-
generateReasonPrompt: row.generateReasonPrompt,
|
|
2693
|
-
metadata: metadataValue,
|
|
2694
|
-
input: inputValue,
|
|
2695
|
-
output: outputValue,
|
|
2696
|
-
additionalContext: additionalLLMContextValue,
|
|
2697
|
-
runtimeContext: runtimeContextValue,
|
|
2698
|
-
entityType: row.entityType,
|
|
2699
|
-
entity: entityValue,
|
|
2700
|
-
entityId: row.entityId,
|
|
2701
|
-
scorerId: row.scorerId,
|
|
2702
|
-
source: row.source,
|
|
2703
|
-
resourceId: row.resourceId,
|
|
2704
|
-
threadId: row.threadId,
|
|
2705
|
-
createdAt: row.createdAt,
|
|
2706
|
-
updatedAt: row.updatedAt
|
|
2707
|
-
};
|
|
3166
|
+
return storage.transformScoreRow(row, {
|
|
3167
|
+
fieldMappings: { additionalContext: "additionalLLMContext" }
|
|
3168
|
+
});
|
|
2708
3169
|
}
|
|
2709
3170
|
async getScoreById({ id }) {
|
|
2710
|
-
const result = await this
|
|
3171
|
+
const result = await this.#client.execute({
|
|
2711
3172
|
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE id = ?`,
|
|
2712
3173
|
args: [id]
|
|
2713
3174
|
});
|
|
@@ -2716,19 +3177,19 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2716
3177
|
async saveScore(score) {
|
|
2717
3178
|
let parsedScore;
|
|
2718
3179
|
try {
|
|
2719
|
-
parsedScore =
|
|
3180
|
+
parsedScore = evals.saveScorePayloadSchema.parse(score);
|
|
2720
3181
|
} catch (error$1) {
|
|
2721
3182
|
throw new error.MastraError(
|
|
2722
3183
|
{
|
|
2723
|
-
id: "
|
|
3184
|
+
id: storage.createStorageErrorId("LIBSQL", "SAVE_SCORE", "VALIDATION_FAILED"),
|
|
2724
3185
|
domain: error.ErrorDomain.STORAGE,
|
|
2725
3186
|
category: error.ErrorCategory.USER,
|
|
2726
3187
|
details: {
|
|
2727
|
-
scorer: score.scorer
|
|
2728
|
-
entityId: score.entityId,
|
|
2729
|
-
entityType: score.entityType,
|
|
2730
|
-
traceId: score.traceId
|
|
2731
|
-
spanId: score.spanId
|
|
3188
|
+
scorer: score.scorer?.id ?? "unknown",
|
|
3189
|
+
entityId: score.entityId ?? "unknown",
|
|
3190
|
+
entityType: score.entityType ?? "unknown",
|
|
3191
|
+
traceId: score.traceId ?? "",
|
|
3192
|
+
spanId: score.spanId ?? ""
|
|
2732
3193
|
}
|
|
2733
3194
|
},
|
|
2734
3195
|
error$1
|
|
@@ -2736,21 +3197,21 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2736
3197
|
}
|
|
2737
3198
|
try {
|
|
2738
3199
|
const id = crypto.randomUUID();
|
|
2739
|
-
|
|
3200
|
+
const now = /* @__PURE__ */ new Date();
|
|
3201
|
+
await this.#db.insert({
|
|
2740
3202
|
tableName: storage.TABLE_SCORERS,
|
|
2741
3203
|
record: {
|
|
3204
|
+
...parsedScore,
|
|
2742
3205
|
id,
|
|
2743
|
-
createdAt:
|
|
2744
|
-
updatedAt:
|
|
2745
|
-
...parsedScore
|
|
3206
|
+
createdAt: now.toISOString(),
|
|
3207
|
+
updatedAt: now.toISOString()
|
|
2746
3208
|
}
|
|
2747
3209
|
});
|
|
2748
|
-
|
|
2749
|
-
return { score: scoreFromDb };
|
|
3210
|
+
return { score: { ...parsedScore, id, createdAt: now, updatedAt: now } };
|
|
2750
3211
|
} catch (error$1) {
|
|
2751
3212
|
throw new error.MastraError(
|
|
2752
3213
|
{
|
|
2753
|
-
id: "
|
|
3214
|
+
id: storage.createStorageErrorId("LIBSQL", "SAVE_SCORE", "FAILED"),
|
|
2754
3215
|
domain: error.ErrorDomain.STORAGE,
|
|
2755
3216
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2756
3217
|
},
|
|
@@ -2758,29 +3219,51 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2758
3219
|
);
|
|
2759
3220
|
}
|
|
2760
3221
|
}
|
|
2761
|
-
async
|
|
3222
|
+
async listScoresByEntityId({
|
|
2762
3223
|
entityId,
|
|
2763
3224
|
entityType,
|
|
2764
3225
|
pagination
|
|
2765
3226
|
}) {
|
|
2766
3227
|
try {
|
|
2767
|
-
const
|
|
3228
|
+
const { page, perPage: perPageInput } = pagination;
|
|
3229
|
+
const countResult = await this.#client.execute({
|
|
3230
|
+
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_SCORERS} WHERE entityId = ? AND entityType = ?`,
|
|
3231
|
+
args: [entityId, entityType]
|
|
3232
|
+
});
|
|
3233
|
+
const total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
3234
|
+
if (total === 0) {
|
|
3235
|
+
return {
|
|
3236
|
+
pagination: {
|
|
3237
|
+
total: 0,
|
|
3238
|
+
page,
|
|
3239
|
+
perPage: perPageInput,
|
|
3240
|
+
hasMore: false
|
|
3241
|
+
},
|
|
3242
|
+
scores: []
|
|
3243
|
+
};
|
|
3244
|
+
}
|
|
3245
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3246
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3247
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3248
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
3249
|
+
const result = await this.#client.execute({
|
|
2768
3250
|
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE entityId = ? AND entityType = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2769
|
-
args: [entityId, entityType,
|
|
3251
|
+
args: [entityId, entityType, limitValue, start]
|
|
2770
3252
|
});
|
|
3253
|
+
const scores = result.rows?.map((row) => this.transformScoreRow(row)) ?? [];
|
|
2771
3254
|
return {
|
|
2772
|
-
scores
|
|
3255
|
+
scores,
|
|
2773
3256
|
pagination: {
|
|
2774
|
-
total
|
|
2775
|
-
page
|
|
2776
|
-
perPage:
|
|
2777
|
-
hasMore:
|
|
3257
|
+
total,
|
|
3258
|
+
page,
|
|
3259
|
+
perPage: perPageForResponse,
|
|
3260
|
+
hasMore: end < total
|
|
2778
3261
|
}
|
|
2779
3262
|
};
|
|
2780
3263
|
} catch (error$1) {
|
|
2781
3264
|
throw new error.MastraError(
|
|
2782
3265
|
{
|
|
2783
|
-
id: "
|
|
3266
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
|
|
2784
3267
|
domain: error.ErrorDomain.STORAGE,
|
|
2785
3268
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2786
3269
|
},
|
|
@@ -2788,36 +3271,40 @@ var ScoresLibSQL = class extends storage.ScoresStorage {
|
|
|
2788
3271
|
);
|
|
2789
3272
|
}
|
|
2790
3273
|
}
|
|
2791
|
-
async
|
|
3274
|
+
async listScoresBySpan({
|
|
2792
3275
|
traceId,
|
|
2793
3276
|
spanId,
|
|
2794
3277
|
pagination
|
|
2795
3278
|
}) {
|
|
2796
3279
|
try {
|
|
2797
|
-
const
|
|
3280
|
+
const { page, perPage: perPageInput } = pagination;
|
|
3281
|
+
const perPage = storage.normalizePerPage(perPageInput, 100);
|
|
3282
|
+
const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
|
|
3283
|
+
const countSQLResult = await this.#client.execute({
|
|
2798
3284
|
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_SCORERS} WHERE traceId = ? AND spanId = ?`,
|
|
2799
3285
|
args: [traceId, spanId]
|
|
2800
3286
|
});
|
|
2801
3287
|
const total = Number(countSQLResult.rows?.[0]?.count ?? 0);
|
|
2802
|
-
const
|
|
3288
|
+
const limitValue = perPageInput === false ? total : perPage;
|
|
3289
|
+
const end = perPageInput === false ? total : start + perPage;
|
|
3290
|
+
const result = await this.#client.execute({
|
|
2803
3291
|
sql: `SELECT * FROM ${storage.TABLE_SCORERS} WHERE traceId = ? AND spanId = ? ORDER BY createdAt DESC LIMIT ? OFFSET ?`,
|
|
2804
|
-
args: [traceId, spanId,
|
|
3292
|
+
args: [traceId, spanId, limitValue, start]
|
|
2805
3293
|
});
|
|
2806
|
-
const
|
|
2807
|
-
const scores = result.rows?.slice(0, pagination.perPage).map((row) => this.transformScoreRow(row)) ?? [];
|
|
3294
|
+
const scores = result.rows?.map((row) => this.transformScoreRow(row)) ?? [];
|
|
2808
3295
|
return {
|
|
2809
3296
|
scores,
|
|
2810
3297
|
pagination: {
|
|
2811
3298
|
total,
|
|
2812
|
-
page
|
|
2813
|
-
perPage:
|
|
2814
|
-
hasMore
|
|
3299
|
+
page,
|
|
3300
|
+
perPage: perPageForResponse,
|
|
3301
|
+
hasMore: end < total
|
|
2815
3302
|
}
|
|
2816
3303
|
};
|
|
2817
3304
|
} catch (error$1) {
|
|
2818
3305
|
throw new error.MastraError(
|
|
2819
3306
|
{
|
|
2820
|
-
id: "
|
|
3307
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_SCORES_BY_SPAN", "FAILED"),
|
|
2821
3308
|
domain: error.ErrorDomain.STORAGE,
|
|
2822
3309
|
category: error.ErrorCategory.THIRD_PARTY
|
|
2823
3310
|
},
|
|
@@ -2845,37 +3332,49 @@ function parseWorkflowRun(row) {
|
|
|
2845
3332
|
};
|
|
2846
3333
|
}
|
|
2847
3334
|
var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
2848
|
-
|
|
2849
|
-
client;
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
constructor({
|
|
2853
|
-
operations,
|
|
2854
|
-
client,
|
|
2855
|
-
maxRetries = 5,
|
|
2856
|
-
initialBackoffMs = 500
|
|
2857
|
-
}) {
|
|
3335
|
+
#db;
|
|
3336
|
+
#client;
|
|
3337
|
+
executeWithRetry;
|
|
3338
|
+
constructor(config) {
|
|
2858
3339
|
super();
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
this
|
|
3340
|
+
const client = resolveClient(config);
|
|
3341
|
+
const maxRetries = config.maxRetries ?? 5;
|
|
3342
|
+
const initialBackoffMs = config.initialBackoffMs ?? 500;
|
|
3343
|
+
this.#client = client;
|
|
3344
|
+
this.#db = new LibSQLDB({ client, maxRetries, initialBackoffMs });
|
|
3345
|
+
this.executeWithRetry = createExecuteWriteOperationWithRetry({
|
|
3346
|
+
logger: this.logger,
|
|
3347
|
+
maxRetries,
|
|
3348
|
+
initialBackoffMs
|
|
3349
|
+
});
|
|
2863
3350
|
this.setupPragmaSettings().catch(
|
|
2864
3351
|
(err) => this.logger.warn("LibSQL Workflows: Failed to setup PRAGMA settings.", err)
|
|
2865
3352
|
);
|
|
2866
3353
|
}
|
|
3354
|
+
async init() {
|
|
3355
|
+
const schema = storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT];
|
|
3356
|
+
await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema });
|
|
3357
|
+
await this.#db.alterTable({
|
|
3358
|
+
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
3359
|
+
schema,
|
|
3360
|
+
ifNotExists: ["resourceId"]
|
|
3361
|
+
});
|
|
3362
|
+
}
|
|
3363
|
+
async dangerouslyClearAll() {
|
|
3364
|
+
await this.#db.deleteData({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
|
|
3365
|
+
}
|
|
2867
3366
|
async setupPragmaSettings() {
|
|
2868
3367
|
try {
|
|
2869
|
-
await this
|
|
3368
|
+
await this.#client.execute("PRAGMA busy_timeout = 10000;");
|
|
2870
3369
|
this.logger.debug("LibSQL Workflows: PRAGMA busy_timeout=10000 set.");
|
|
2871
3370
|
try {
|
|
2872
|
-
await this
|
|
3371
|
+
await this.#client.execute("PRAGMA journal_mode = WAL;");
|
|
2873
3372
|
this.logger.debug("LibSQL Workflows: PRAGMA journal_mode=WAL set.");
|
|
2874
3373
|
} catch {
|
|
2875
3374
|
this.logger.debug("LibSQL Workflows: WAL mode not supported, using default journal mode.");
|
|
2876
3375
|
}
|
|
2877
3376
|
try {
|
|
2878
|
-
await this
|
|
3377
|
+
await this.#client.execute("PRAGMA synchronous = NORMAL;");
|
|
2879
3378
|
this.logger.debug("LibSQL Workflows: PRAGMA synchronous=NORMAL set.");
|
|
2880
3379
|
} catch {
|
|
2881
3380
|
this.logger.debug("LibSQL Workflows: Failed to set synchronous mode.");
|
|
@@ -2884,53 +3383,15 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
2884
3383
|
this.logger.warn("LibSQL Workflows: Failed to set PRAGMA settings.", err);
|
|
2885
3384
|
}
|
|
2886
3385
|
}
|
|
2887
|
-
async executeWithRetry(operation) {
|
|
2888
|
-
let attempts = 0;
|
|
2889
|
-
let backoff = this.initialBackoffMs;
|
|
2890
|
-
while (attempts < this.maxRetries) {
|
|
2891
|
-
try {
|
|
2892
|
-
return await operation();
|
|
2893
|
-
} catch (error) {
|
|
2894
|
-
this.logger.debug("LibSQL Workflows: Error caught in retry loop", {
|
|
2895
|
-
errorType: error.constructor.name,
|
|
2896
|
-
errorCode: error.code,
|
|
2897
|
-
errorMessage: error.message,
|
|
2898
|
-
attempts,
|
|
2899
|
-
maxRetries: this.maxRetries
|
|
2900
|
-
});
|
|
2901
|
-
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");
|
|
2902
|
-
if (isLockError) {
|
|
2903
|
-
attempts++;
|
|
2904
|
-
if (attempts >= this.maxRetries) {
|
|
2905
|
-
this.logger.error(
|
|
2906
|
-
`LibSQL Workflows: Operation failed after ${this.maxRetries} attempts due to database lock: ${error.message}`,
|
|
2907
|
-
{ error, attempts, maxRetries: this.maxRetries }
|
|
2908
|
-
);
|
|
2909
|
-
throw error;
|
|
2910
|
-
}
|
|
2911
|
-
this.logger.warn(
|
|
2912
|
-
`LibSQL Workflows: Attempt ${attempts} failed due to database lock. Retrying in ${backoff}ms...`,
|
|
2913
|
-
{ errorMessage: error.message, attempts, backoff, maxRetries: this.maxRetries }
|
|
2914
|
-
);
|
|
2915
|
-
await new Promise((resolve) => setTimeout(resolve, backoff));
|
|
2916
|
-
backoff *= 2;
|
|
2917
|
-
} else {
|
|
2918
|
-
this.logger.error("LibSQL Workflows: Non-lock error occurred, not retrying", { error });
|
|
2919
|
-
throw error;
|
|
2920
|
-
}
|
|
2921
|
-
}
|
|
2922
|
-
}
|
|
2923
|
-
throw new Error("LibSQL Workflows: Max retries reached, but no error was re-thrown from the loop.");
|
|
2924
|
-
}
|
|
2925
3386
|
async updateWorkflowResults({
|
|
2926
3387
|
workflowName,
|
|
2927
3388
|
runId,
|
|
2928
3389
|
stepId,
|
|
2929
3390
|
result,
|
|
2930
|
-
|
|
3391
|
+
requestContext
|
|
2931
3392
|
}) {
|
|
2932
3393
|
return this.executeWithRetry(async () => {
|
|
2933
|
-
const tx = await this
|
|
3394
|
+
const tx = await this.#client.transaction("write");
|
|
2934
3395
|
try {
|
|
2935
3396
|
const existingSnapshotResult = await tx.execute({
|
|
2936
3397
|
sql: `SELECT snapshot FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} WHERE workflow_name = ? AND run_id = ?`,
|
|
@@ -2943,20 +3404,21 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
2943
3404
|
activePaths: [],
|
|
2944
3405
|
timestamp: Date.now(),
|
|
2945
3406
|
suspendedPaths: {},
|
|
3407
|
+
activeStepsPath: {},
|
|
2946
3408
|
resumeLabels: {},
|
|
2947
3409
|
serializedStepGraph: [],
|
|
3410
|
+
status: "pending",
|
|
2948
3411
|
value: {},
|
|
2949
3412
|
waitingPaths: {},
|
|
2950
|
-
status: "pending",
|
|
2951
3413
|
runId,
|
|
2952
|
-
|
|
3414
|
+
requestContext: {}
|
|
2953
3415
|
};
|
|
2954
3416
|
} else {
|
|
2955
3417
|
const existingSnapshot = existingSnapshotResult.rows[0].snapshot;
|
|
2956
3418
|
snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
|
|
2957
3419
|
}
|
|
2958
3420
|
snapshot.context[stepId] = result;
|
|
2959
|
-
snapshot.
|
|
3421
|
+
snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
|
|
2960
3422
|
await tx.execute({
|
|
2961
3423
|
sql: `UPDATE ${storage.TABLE_WORKFLOW_SNAPSHOT} SET snapshot = ? WHERE workflow_name = ? AND run_id = ?`,
|
|
2962
3424
|
args: [JSON.stringify(snapshot), workflowName, runId]
|
|
@@ -2969,7 +3431,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
2969
3431
|
}
|
|
2970
3432
|
throw error;
|
|
2971
3433
|
}
|
|
2972
|
-
});
|
|
3434
|
+
}, "updateWorkflowResults");
|
|
2973
3435
|
}
|
|
2974
3436
|
async updateWorkflowState({
|
|
2975
3437
|
workflowName,
|
|
@@ -2977,7 +3439,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
2977
3439
|
opts
|
|
2978
3440
|
}) {
|
|
2979
3441
|
return this.executeWithRetry(async () => {
|
|
2980
|
-
const tx = await this
|
|
3442
|
+
const tx = await this.#client.transaction("write");
|
|
2981
3443
|
try {
|
|
2982
3444
|
const existingSnapshotResult = await tx.execute({
|
|
2983
3445
|
sql: `SELECT snapshot FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} WHERE workflow_name = ? AND run_id = ?`,
|
|
@@ -3006,24 +3468,27 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3006
3468
|
}
|
|
3007
3469
|
throw error;
|
|
3008
3470
|
}
|
|
3009
|
-
});
|
|
3471
|
+
}, "updateWorkflowState");
|
|
3010
3472
|
}
|
|
3011
3473
|
async persistWorkflowSnapshot({
|
|
3012
3474
|
workflowName,
|
|
3013
3475
|
runId,
|
|
3014
3476
|
resourceId,
|
|
3015
|
-
snapshot
|
|
3477
|
+
snapshot,
|
|
3478
|
+
createdAt,
|
|
3479
|
+
updatedAt
|
|
3016
3480
|
}) {
|
|
3481
|
+
const now = /* @__PURE__ */ new Date();
|
|
3017
3482
|
const data = {
|
|
3018
3483
|
workflow_name: workflowName,
|
|
3019
3484
|
run_id: runId,
|
|
3020
3485
|
resourceId,
|
|
3021
3486
|
snapshot,
|
|
3022
|
-
createdAt:
|
|
3023
|
-
updatedAt:
|
|
3487
|
+
createdAt: createdAt ?? now,
|
|
3488
|
+
updatedAt: updatedAt ?? now
|
|
3024
3489
|
};
|
|
3025
3490
|
this.logger.debug("Persisting workflow snapshot", { workflowName, runId, data });
|
|
3026
|
-
await this.
|
|
3491
|
+
await this.#db.insert({
|
|
3027
3492
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
3028
3493
|
record: data
|
|
3029
3494
|
});
|
|
@@ -3033,7 +3498,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3033
3498
|
runId
|
|
3034
3499
|
}) {
|
|
3035
3500
|
this.logger.debug("Loading workflow snapshot", { workflowName, runId });
|
|
3036
|
-
const d = await this.
|
|
3501
|
+
const d = await this.#db.select({
|
|
3037
3502
|
tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
|
|
3038
3503
|
keys: { workflow_name: workflowName, run_id: runId }
|
|
3039
3504
|
});
|
|
@@ -3055,7 +3520,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3055
3520
|
}
|
|
3056
3521
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
3057
3522
|
try {
|
|
3058
|
-
const result = await this
|
|
3523
|
+
const result = await this.#client.execute({
|
|
3059
3524
|
sql: `SELECT * FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} ${whereClause} ORDER BY createdAt DESC LIMIT 1`,
|
|
3060
3525
|
args
|
|
3061
3526
|
});
|
|
@@ -3066,7 +3531,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3066
3531
|
} catch (error$1) {
|
|
3067
3532
|
throw new error.MastraError(
|
|
3068
3533
|
{
|
|
3069
|
-
id: "
|
|
3534
|
+
id: storage.createStorageErrorId("LIBSQL", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
3070
3535
|
domain: error.ErrorDomain.STORAGE,
|
|
3071
3536
|
category: error.ErrorCategory.THIRD_PARTY
|
|
3072
3537
|
},
|
|
@@ -3074,13 +3539,34 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3074
3539
|
);
|
|
3075
3540
|
}
|
|
3076
3541
|
}
|
|
3077
|
-
async
|
|
3542
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
3543
|
+
return this.executeWithRetry(async () => {
|
|
3544
|
+
try {
|
|
3545
|
+
await this.#client.execute({
|
|
3546
|
+
sql: `DELETE FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} WHERE workflow_name = ? AND run_id = ?`,
|
|
3547
|
+
args: [workflowName, runId]
|
|
3548
|
+
});
|
|
3549
|
+
} catch (error$1) {
|
|
3550
|
+
throw new error.MastraError(
|
|
3551
|
+
{
|
|
3552
|
+
id: storage.createStorageErrorId("LIBSQL", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
|
|
3553
|
+
domain: error.ErrorDomain.STORAGE,
|
|
3554
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
3555
|
+
details: { runId, workflowName }
|
|
3556
|
+
},
|
|
3557
|
+
error$1
|
|
3558
|
+
);
|
|
3559
|
+
}
|
|
3560
|
+
}, "deleteWorkflowRunById");
|
|
3561
|
+
}
|
|
3562
|
+
async listWorkflowRuns({
|
|
3078
3563
|
workflowName,
|
|
3079
3564
|
fromDate,
|
|
3080
3565
|
toDate,
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
resourceId
|
|
3566
|
+
page,
|
|
3567
|
+
perPage,
|
|
3568
|
+
resourceId,
|
|
3569
|
+
status
|
|
3084
3570
|
} = {}) {
|
|
3085
3571
|
try {
|
|
3086
3572
|
const conditions = [];
|
|
@@ -3089,6 +3575,10 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3089
3575
|
conditions.push("workflow_name = ?");
|
|
3090
3576
|
args.push(workflowName);
|
|
3091
3577
|
}
|
|
3578
|
+
if (status) {
|
|
3579
|
+
conditions.push("json_extract(snapshot, '$.status') = ?");
|
|
3580
|
+
args.push(status);
|
|
3581
|
+
}
|
|
3092
3582
|
if (fromDate) {
|
|
3093
3583
|
conditions.push("createdAt >= ?");
|
|
3094
3584
|
args.push(fromDate.toISOString());
|
|
@@ -3098,7 +3588,7 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3098
3588
|
args.push(toDate.toISOString());
|
|
3099
3589
|
}
|
|
3100
3590
|
if (resourceId) {
|
|
3101
|
-
const hasResourceId = await this.
|
|
3591
|
+
const hasResourceId = await this.#db.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
|
|
3102
3592
|
if (hasResourceId) {
|
|
3103
3593
|
conditions.push("resourceId = ?");
|
|
3104
3594
|
args.push(resourceId);
|
|
@@ -3108,23 +3598,26 @@ var WorkflowsLibSQL = class extends storage.WorkflowsStorage {
|
|
|
3108
3598
|
}
|
|
3109
3599
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
3110
3600
|
let total = 0;
|
|
3111
|
-
|
|
3112
|
-
|
|
3601
|
+
const usePagination = typeof perPage === "number" && typeof page === "number";
|
|
3602
|
+
if (usePagination) {
|
|
3603
|
+
const countResult = await this.#client.execute({
|
|
3113
3604
|
sql: `SELECT COUNT(*) as count FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} ${whereClause}`,
|
|
3114
3605
|
args
|
|
3115
3606
|
});
|
|
3116
3607
|
total = Number(countResult.rows?.[0]?.count ?? 0);
|
|
3117
3608
|
}
|
|
3118
|
-
const
|
|
3119
|
-
|
|
3120
|
-
|
|
3609
|
+
const normalizedPerPage = usePagination ? storage.normalizePerPage(perPage, Number.MAX_SAFE_INTEGER) : 0;
|
|
3610
|
+
const offset = usePagination ? page * normalizedPerPage : 0;
|
|
3611
|
+
const result = await this.#client.execute({
|
|
3612
|
+
sql: `SELECT * FROM ${storage.TABLE_WORKFLOW_SNAPSHOT} ${whereClause} ORDER BY createdAt DESC${usePagination ? ` LIMIT ? OFFSET ?` : ""}`,
|
|
3613
|
+
args: usePagination ? [...args, normalizedPerPage, offset] : args
|
|
3121
3614
|
});
|
|
3122
3615
|
const runs = (result.rows || []).map((row) => parseWorkflowRun(row));
|
|
3123
3616
|
return { runs, total: total || runs.length };
|
|
3124
3617
|
} catch (error$1) {
|
|
3125
3618
|
throw new error.MastraError(
|
|
3126
3619
|
{
|
|
3127
|
-
id: "
|
|
3620
|
+
id: storage.createStorageErrorId("LIBSQL", "LIST_WORKFLOW_RUNS", "FAILED"),
|
|
3128
3621
|
domain: error.ErrorDomain.STORAGE,
|
|
3129
3622
|
category: error.ErrorCategory.THIRD_PARTY
|
|
3130
3623
|
},
|
|
@@ -3141,7 +3634,10 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3141
3634
|
initialBackoffMs;
|
|
3142
3635
|
stores;
|
|
3143
3636
|
constructor(config) {
|
|
3144
|
-
|
|
3637
|
+
if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
|
|
3638
|
+
throw new Error("LibSQLStore: id must be provided and cannot be empty.");
|
|
3639
|
+
}
|
|
3640
|
+
super({ id: config.id, name: `LibSQLStore`, disableInit: config.disableInit });
|
|
3145
3641
|
this.maxRetries = config.maxRetries ?? 5;
|
|
3146
3642
|
this.initialBackoffMs = config.initialBackoffMs ?? 100;
|
|
3147
3643
|
if ("url" in config) {
|
|
@@ -3159,23 +3655,22 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3159
3655
|
} else {
|
|
3160
3656
|
this.client = config.client;
|
|
3161
3657
|
}
|
|
3162
|
-
const
|
|
3658
|
+
const domainConfig = {
|
|
3163
3659
|
client: this.client,
|
|
3164
3660
|
maxRetries: this.maxRetries,
|
|
3165
3661
|
initialBackoffMs: this.initialBackoffMs
|
|
3166
|
-
}
|
|
3167
|
-
const scores = new ScoresLibSQL(
|
|
3168
|
-
const workflows = new WorkflowsLibSQL(
|
|
3169
|
-
const memory = new MemoryLibSQL(
|
|
3170
|
-
const
|
|
3171
|
-
const
|
|
3662
|
+
};
|
|
3663
|
+
const scores = new ScoresLibSQL(domainConfig);
|
|
3664
|
+
const workflows = new WorkflowsLibSQL(domainConfig);
|
|
3665
|
+
const memory = new MemoryLibSQL(domainConfig);
|
|
3666
|
+
const observability = new ObservabilityLibSQL(domainConfig);
|
|
3667
|
+
const agents = new AgentsLibSQL(domainConfig);
|
|
3172
3668
|
this.stores = {
|
|
3173
|
-
operations,
|
|
3174
3669
|
scores,
|
|
3175
3670
|
workflows,
|
|
3176
3671
|
memory,
|
|
3177
|
-
|
|
3178
|
-
|
|
3672
|
+
observability,
|
|
3673
|
+
agents
|
|
3179
3674
|
};
|
|
3180
3675
|
}
|
|
3181
3676
|
get supports() {
|
|
@@ -3185,56 +3680,14 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3185
3680
|
hasColumn: true,
|
|
3186
3681
|
createTable: true,
|
|
3187
3682
|
deleteMessages: true,
|
|
3188
|
-
|
|
3189
|
-
|
|
3683
|
+
observabilityInstance: true,
|
|
3684
|
+
listScoresBySpan: true,
|
|
3685
|
+
agents: true
|
|
3190
3686
|
};
|
|
3191
3687
|
}
|
|
3192
|
-
async createTable({
|
|
3193
|
-
tableName,
|
|
3194
|
-
schema
|
|
3195
|
-
}) {
|
|
3196
|
-
await this.stores.operations.createTable({ tableName, schema });
|
|
3197
|
-
}
|
|
3198
|
-
/**
|
|
3199
|
-
* Alters table schema to add columns if they don't exist
|
|
3200
|
-
* @param tableName Name of the table
|
|
3201
|
-
* @param schema Schema of the table
|
|
3202
|
-
* @param ifNotExists Array of column names to add if they don't exist
|
|
3203
|
-
*/
|
|
3204
|
-
async alterTable({
|
|
3205
|
-
tableName,
|
|
3206
|
-
schema,
|
|
3207
|
-
ifNotExists
|
|
3208
|
-
}) {
|
|
3209
|
-
await this.stores.operations.alterTable({ tableName, schema, ifNotExists });
|
|
3210
|
-
}
|
|
3211
|
-
async clearTable({ tableName }) {
|
|
3212
|
-
await this.stores.operations.clearTable({ tableName });
|
|
3213
|
-
}
|
|
3214
|
-
async dropTable({ tableName }) {
|
|
3215
|
-
await this.stores.operations.dropTable({ tableName });
|
|
3216
|
-
}
|
|
3217
|
-
insert(args) {
|
|
3218
|
-
return this.stores.operations.insert(args);
|
|
3219
|
-
}
|
|
3220
|
-
batchInsert(args) {
|
|
3221
|
-
return this.stores.operations.batchInsert(args);
|
|
3222
|
-
}
|
|
3223
|
-
async load({ tableName, keys }) {
|
|
3224
|
-
return this.stores.operations.load({ tableName, keys });
|
|
3225
|
-
}
|
|
3226
3688
|
async getThreadById({ threadId }) {
|
|
3227
3689
|
return this.stores.memory.getThreadById({ threadId });
|
|
3228
3690
|
}
|
|
3229
|
-
/**
|
|
3230
|
-
* @deprecated use getThreadsByResourceIdPaginated instead for paginated results.
|
|
3231
|
-
*/
|
|
3232
|
-
async getThreadsByResourceId(args) {
|
|
3233
|
-
return this.stores.memory.getThreadsByResourceId(args);
|
|
3234
|
-
}
|
|
3235
|
-
async getThreadsByResourceIdPaginated(args) {
|
|
3236
|
-
return this.stores.memory.getThreadsByResourceIdPaginated(args);
|
|
3237
|
-
}
|
|
3238
3691
|
async saveThread({ thread }) {
|
|
3239
3692
|
return this.stores.memory.saveThread({ thread });
|
|
3240
3693
|
}
|
|
@@ -3248,24 +3701,12 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3248
3701
|
async deleteThread({ threadId }) {
|
|
3249
3702
|
return this.stores.memory.deleteThread({ threadId });
|
|
3250
3703
|
}
|
|
3251
|
-
async
|
|
3252
|
-
|
|
3253
|
-
selectBy,
|
|
3254
|
-
format
|
|
3255
|
-
}) {
|
|
3256
|
-
return this.stores.memory.getMessages({ threadId, selectBy, format });
|
|
3257
|
-
}
|
|
3258
|
-
async getMessagesById({
|
|
3259
|
-
messageIds,
|
|
3260
|
-
format
|
|
3261
|
-
}) {
|
|
3262
|
-
return this.stores.memory.getMessagesById({ messageIds, format });
|
|
3263
|
-
}
|
|
3264
|
-
async getMessagesPaginated(args) {
|
|
3265
|
-
return this.stores.memory.getMessagesPaginated(args);
|
|
3704
|
+
async listMessagesById({ messageIds }) {
|
|
3705
|
+
return this.stores.memory.listMessagesById({ messageIds });
|
|
3266
3706
|
}
|
|
3267
3707
|
async saveMessages(args) {
|
|
3268
|
-
|
|
3708
|
+
const result = await this.stores.memory.saveMessages({ messages: args.messages });
|
|
3709
|
+
return { messages: result.messages };
|
|
3269
3710
|
}
|
|
3270
3711
|
async updateMessages({
|
|
3271
3712
|
messages
|
|
@@ -3275,40 +3716,33 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3275
3716
|
async deleteMessages(messageIds) {
|
|
3276
3717
|
return this.stores.memory.deleteMessages(messageIds);
|
|
3277
3718
|
}
|
|
3278
|
-
/** @deprecated use getEvals instead */
|
|
3279
|
-
async getEvalsByAgentName(agentName, type) {
|
|
3280
|
-
return this.stores.legacyEvals.getEvalsByAgentName(agentName, type);
|
|
3281
|
-
}
|
|
3282
|
-
async getEvals(options = {}) {
|
|
3283
|
-
return this.stores.legacyEvals.getEvals(options);
|
|
3284
|
-
}
|
|
3285
3719
|
async getScoreById({ id }) {
|
|
3286
3720
|
return this.stores.scores.getScoreById({ id });
|
|
3287
3721
|
}
|
|
3288
3722
|
async saveScore(score) {
|
|
3289
3723
|
return this.stores.scores.saveScore(score);
|
|
3290
3724
|
}
|
|
3291
|
-
async
|
|
3725
|
+
async listScoresByScorerId({
|
|
3292
3726
|
scorerId,
|
|
3293
3727
|
entityId,
|
|
3294
3728
|
entityType,
|
|
3295
3729
|
source,
|
|
3296
3730
|
pagination
|
|
3297
3731
|
}) {
|
|
3298
|
-
return this.stores.scores.
|
|
3732
|
+
return this.stores.scores.listScoresByScorerId({ scorerId, entityId, entityType, source, pagination });
|
|
3299
3733
|
}
|
|
3300
|
-
async
|
|
3734
|
+
async listScoresByRunId({
|
|
3301
3735
|
runId,
|
|
3302
3736
|
pagination
|
|
3303
3737
|
}) {
|
|
3304
|
-
return this.stores.scores.
|
|
3738
|
+
return this.stores.scores.listScoresByRunId({ runId, pagination });
|
|
3305
3739
|
}
|
|
3306
|
-
async
|
|
3740
|
+
async listScoresByEntityId({
|
|
3307
3741
|
entityId,
|
|
3308
3742
|
entityType,
|
|
3309
3743
|
pagination
|
|
3310
3744
|
}) {
|
|
3311
|
-
return this.stores.scores.
|
|
3745
|
+
return this.stores.scores.listScoresByEntityId({ entityId, entityType, pagination });
|
|
3312
3746
|
}
|
|
3313
3747
|
/**
|
|
3314
3748
|
* WORKFLOWS
|
|
@@ -3318,9 +3752,9 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3318
3752
|
runId,
|
|
3319
3753
|
stepId,
|
|
3320
3754
|
result,
|
|
3321
|
-
|
|
3755
|
+
requestContext
|
|
3322
3756
|
}) {
|
|
3323
|
-
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result,
|
|
3757
|
+
return this.stores.workflows.updateWorkflowResults({ workflowName, runId, stepId, result, requestContext });
|
|
3324
3758
|
}
|
|
3325
3759
|
async updateWorkflowState({
|
|
3326
3760
|
workflowName,
|
|
@@ -3343,15 +3777,8 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3343
3777
|
}) {
|
|
3344
3778
|
return this.stores.workflows.loadWorkflowSnapshot({ workflowName, runId });
|
|
3345
3779
|
}
|
|
3346
|
-
async
|
|
3347
|
-
|
|
3348
|
-
fromDate,
|
|
3349
|
-
toDate,
|
|
3350
|
-
limit,
|
|
3351
|
-
offset,
|
|
3352
|
-
resourceId
|
|
3353
|
-
} = {}) {
|
|
3354
|
-
return this.stores.workflows.getWorkflowRuns({ workflowName, fromDate, toDate, limit, offset, resourceId });
|
|
3780
|
+
async listWorkflowRuns(args = {}) {
|
|
3781
|
+
return this.stores.workflows.listWorkflowRuns(args);
|
|
3355
3782
|
}
|
|
3356
3783
|
async getWorkflowRunById({
|
|
3357
3784
|
runId,
|
|
@@ -3359,6 +3786,9 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3359
3786
|
}) {
|
|
3360
3787
|
return this.stores.workflows.getWorkflowRunById({ runId, workflowName });
|
|
3361
3788
|
}
|
|
3789
|
+
async deleteWorkflowRunById({ runId, workflowName }) {
|
|
3790
|
+
return this.stores.workflows.deleteWorkflowRunById({ runId, workflowName });
|
|
3791
|
+
}
|
|
3362
3792
|
async getResourceById({ resourceId }) {
|
|
3363
3793
|
return this.stores.memory.getResourceById({ resourceId });
|
|
3364
3794
|
}
|
|
@@ -3372,30 +3802,30 @@ var LibSQLStore = class extends storage.MastraStorage {
|
|
|
3372
3802
|
}) {
|
|
3373
3803
|
return this.stores.memory.updateResource({ resourceId, workingMemory, metadata });
|
|
3374
3804
|
}
|
|
3375
|
-
async
|
|
3376
|
-
return this.stores.observability.
|
|
3805
|
+
async createSpan(span) {
|
|
3806
|
+
return this.stores.observability.createSpan(span);
|
|
3377
3807
|
}
|
|
3378
|
-
async
|
|
3379
|
-
return this.stores.observability.
|
|
3808
|
+
async updateSpan(params) {
|
|
3809
|
+
return this.stores.observability.updateSpan(params);
|
|
3380
3810
|
}
|
|
3381
|
-
async
|
|
3382
|
-
return this.stores.observability.
|
|
3811
|
+
async getTrace(traceId) {
|
|
3812
|
+
return this.stores.observability.getTrace(traceId);
|
|
3383
3813
|
}
|
|
3384
|
-
async
|
|
3385
|
-
return this.stores.observability.
|
|
3814
|
+
async getTracesPaginated(args) {
|
|
3815
|
+
return this.stores.observability.getTracesPaginated(args);
|
|
3386
3816
|
}
|
|
3387
|
-
async
|
|
3817
|
+
async listScoresBySpan({
|
|
3388
3818
|
traceId,
|
|
3389
3819
|
spanId,
|
|
3390
3820
|
pagination
|
|
3391
3821
|
}) {
|
|
3392
|
-
return this.stores.scores.
|
|
3822
|
+
return this.stores.scores.listScoresBySpan({ traceId, spanId, pagination });
|
|
3393
3823
|
}
|
|
3394
|
-
async
|
|
3395
|
-
return this.stores.observability.
|
|
3824
|
+
async batchCreateSpans(args) {
|
|
3825
|
+
return this.stores.observability.batchCreateSpans(args);
|
|
3396
3826
|
}
|
|
3397
|
-
async
|
|
3398
|
-
return this.stores.observability.
|
|
3827
|
+
async batchUpdateSpans(args) {
|
|
3828
|
+
return this.stores.observability.batchUpdateSpans(args);
|
|
3399
3829
|
}
|
|
3400
3830
|
};
|
|
3401
3831
|
|