@axiom-lattice/core 2.1.12 → 2.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  AgentType: () => import_protocols.AgentType,
38
38
  ChunkBuffer: () => ChunkBuffer,
39
39
  ChunkBufferLatticeManager: () => ChunkBufferLatticeManager,
40
+ DefaultScheduleClient: () => DefaultScheduleClient,
40
41
  EmbeddingsLatticeManager: () => EmbeddingsLatticeManager,
41
42
  GraphBuildOptions: () => import_protocols.GraphBuildOptions,
42
43
  InMemoryAssistantStore: () => InMemoryAssistantStore,
@@ -44,15 +45,20 @@ __export(index_exports, {
44
45
  InMemoryThreadStore: () => InMemoryThreadStore,
45
46
  MemoryLatticeManager: () => MemoryLatticeManager,
46
47
  MemoryQueueClient: () => MemoryQueueClient,
48
+ MemoryScheduleStorage: () => MemoryScheduleStorage,
47
49
  MemoryType: () => import_protocols2.MemoryType,
48
50
  ModelLatticeManager: () => ModelLatticeManager,
51
+ PostgresDatabase: () => PostgresDatabase,
49
52
  Protocols: () => Protocols,
50
53
  QueueLatticeManager: () => QueueLatticeManager,
54
+ ScheduleLatticeManager: () => ScheduleLatticeManager,
55
+ SqlDatabaseManager: () => SqlDatabaseManager,
51
56
  StoreLatticeManager: () => StoreLatticeManager,
52
57
  ThreadStatus: () => ThreadStatus,
53
58
  ToolLatticeManager: () => ToolLatticeManager,
54
59
  VectorStoreLatticeManager: () => VectorStoreLatticeManager,
55
60
  agentLatticeManager: () => agentLatticeManager,
61
+ describeCronExpression: () => describeCronExpression,
56
62
  embeddingsLatticeManager: () => embeddingsLatticeManager,
57
63
  eventBus: () => eventBus,
58
64
  eventBusDefault: () => event_bus_default,
@@ -66,7 +72,9 @@ __export(index_exports, {
66
72
  getEmbeddingsClient: () => getEmbeddingsClient,
67
73
  getEmbeddingsLattice: () => getEmbeddingsLattice,
68
74
  getModelLattice: () => getModelLattice,
75
+ getNextCronTime: () => getNextCronTime,
69
76
  getQueueLattice: () => getQueueLattice,
77
+ getScheduleLattice: () => getScheduleLattice,
70
78
  getStoreLattice: () => getStoreLattice,
71
79
  getToolClient: () => getToolClient,
72
80
  getToolDefinition: () => getToolDefinition,
@@ -74,7 +82,9 @@ __export(index_exports, {
74
82
  getVectorStoreClient: () => getVectorStoreClient,
75
83
  getVectorStoreLattice: () => getVectorStoreLattice,
76
84
  hasChunkBuffer: () => hasChunkBuffer,
85
+ isValidCronExpression: () => isValidCronExpression,
77
86
  modelLatticeManager: () => modelLatticeManager,
87
+ parseCronExpression: () => parseCronExpression,
78
88
  queueLatticeManager: () => queueLatticeManager,
79
89
  registerAgentLattice: () => registerAgentLattice,
80
90
  registerAgentLattices: () => registerAgentLattices,
@@ -83,9 +93,12 @@ __export(index_exports, {
83
93
  registerEmbeddingsLattice: () => registerEmbeddingsLattice,
84
94
  registerModelLattice: () => registerModelLattice,
85
95
  registerQueueLattice: () => registerQueueLattice,
96
+ registerScheduleLattice: () => registerScheduleLattice,
86
97
  registerStoreLattice: () => registerStoreLattice,
87
98
  registerToolLattice: () => registerToolLattice,
88
99
  registerVectorStoreLattice: () => registerVectorStoreLattice,
100
+ scheduleLatticeManager: () => scheduleLatticeManager,
101
+ sqlDatabaseManager: () => sqlDatabaseManager,
89
102
  storeLatticeManager: () => storeLatticeManager,
90
103
  toolLatticeManager: () => toolLatticeManager,
91
104
  validateAgentInput: () => validateAgentInput,
@@ -680,6 +693,538 @@ registerToolLattice(
680
693
  }
681
694
  );
682
695
 
696
+ // src/tool_lattice/sql/list_tables_sql.ts
697
+ var import_zod3 = __toESM(require("zod"));
698
+
699
+ // src/tool_lattice/sql/SqlDatabaseManager.ts
700
+ var PostgresDatabase = class {
701
+ constructor(config) {
702
+ // pg.Pool
703
+ this.connected = false;
704
+ this.config = config;
705
+ }
706
+ async connect() {
707
+ if (this.connected) return;
708
+ try {
709
+ const { Pool } = await import("pg");
710
+ const poolConfig = this.config.connectionString ? { connectionString: this.config.connectionString } : {
711
+ host: this.config.host || "localhost",
712
+ port: this.config.port || 5432,
713
+ database: this.config.database,
714
+ user: this.config.user,
715
+ password: this.config.password,
716
+ ssl: this.config.ssl ? { rejectUnauthorized: false } : void 0
717
+ };
718
+ this.pool = new Pool(poolConfig);
719
+ const client = await this.pool.connect();
720
+ client.release();
721
+ this.connected = true;
722
+ } catch (error) {
723
+ throw new Error(`Failed to connect to PostgreSQL: ${error}`);
724
+ }
725
+ }
726
+ async disconnect() {
727
+ if (this.pool) {
728
+ await this.pool.end();
729
+ this.connected = false;
730
+ }
731
+ }
732
+ async listTables() {
733
+ await this.ensureConnected();
734
+ const query = `
735
+ SELECT table_name, table_schema
736
+ FROM information_schema.tables
737
+ WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
738
+ AND table_type = 'BASE TABLE'
739
+ ORDER BY table_schema, table_name;
740
+ `;
741
+ const result = await this.pool.query(query);
742
+ return result.rows.map((row) => ({
743
+ name: row.table_name,
744
+ schema: row.table_schema
745
+ }));
746
+ }
747
+ async getTableInfo(tables) {
748
+ await this.ensureConnected();
749
+ const schemas = [];
750
+ for (const tableName of tables) {
751
+ const columnQuery = `
752
+ SELECT
753
+ c.column_name,
754
+ c.data_type,
755
+ c.is_nullable,
756
+ c.column_default,
757
+ CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_key,
758
+ CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as is_foreign_key,
759
+ fk.foreign_table_name,
760
+ fk.foreign_column_name
761
+ FROM information_schema.columns c
762
+ LEFT JOIN (
763
+ SELECT ku.column_name, ku.table_name
764
+ FROM information_schema.table_constraints tc
765
+ JOIN information_schema.key_column_usage ku
766
+ ON tc.constraint_name = ku.constraint_name
767
+ WHERE tc.constraint_type = 'PRIMARY KEY'
768
+ ) pk ON c.column_name = pk.column_name AND c.table_name = pk.table_name
769
+ LEFT JOIN (
770
+ SELECT
771
+ kcu.column_name,
772
+ kcu.table_name,
773
+ ccu.table_name as foreign_table_name,
774
+ ccu.column_name as foreign_column_name
775
+ FROM information_schema.table_constraints tc
776
+ JOIN information_schema.key_column_usage kcu
777
+ ON tc.constraint_name = kcu.constraint_name
778
+ JOIN information_schema.constraint_column_usage ccu
779
+ ON tc.constraint_name = ccu.constraint_name
780
+ WHERE tc.constraint_type = 'FOREIGN KEY'
781
+ ) fk ON c.column_name = fk.column_name AND c.table_name = fk.table_name
782
+ WHERE c.table_name = $1
783
+ ORDER BY c.ordinal_position;
784
+ `;
785
+ const columnResult = await this.pool.query(columnQuery, [tableName]);
786
+ const columns = columnResult.rows.map((row) => ({
787
+ name: row.column_name,
788
+ type: row.data_type,
789
+ nullable: row.is_nullable === "YES",
790
+ default: row.column_default,
791
+ isPrimaryKey: row.is_primary_key,
792
+ isForeignKey: row.is_foreign_key,
793
+ foreignKeyRef: row.is_foreign_key ? `${row.foreign_table_name}.${row.foreign_column_name}` : void 0
794
+ }));
795
+ let sampleRows = [];
796
+ try {
797
+ const sampleQuery = `SELECT * FROM "${tableName}" LIMIT 3`;
798
+ const sampleResult = await this.pool.query(sampleQuery);
799
+ sampleRows = sampleResult.rows;
800
+ } catch {
801
+ }
802
+ schemas.push({
803
+ tableName,
804
+ columns,
805
+ sampleRows
806
+ });
807
+ }
808
+ return schemas;
809
+ }
810
+ async executeQuery(query) {
811
+ await this.ensureConnected();
812
+ const result = await this.pool.query(query);
813
+ return {
814
+ rows: result.rows,
815
+ rowCount: result.rowCount || result.rows.length,
816
+ fields: result.fields?.map((f) => f.name)
817
+ };
818
+ }
819
+ getDatabaseType() {
820
+ return "postgres";
821
+ }
822
+ async ensureConnected() {
823
+ if (!this.connected) {
824
+ await this.connect();
825
+ }
826
+ }
827
+ };
828
+ var SqlDatabaseManager = class _SqlDatabaseManager {
829
+ constructor() {
830
+ this.databases = /* @__PURE__ */ new Map();
831
+ this.defaultDatabaseKey = null;
832
+ }
833
+ /**
834
+ * Get the singleton instance
835
+ */
836
+ static getInstance() {
837
+ if (!_SqlDatabaseManager.instance) {
838
+ _SqlDatabaseManager.instance = new _SqlDatabaseManager();
839
+ }
840
+ return _SqlDatabaseManager.instance;
841
+ }
842
+ /**
843
+ * Register a database connection
844
+ * @param key - Unique identifier for the database
845
+ * @param config - Database configuration
846
+ */
847
+ registerDatabase(key, config) {
848
+ let database;
849
+ switch (config.type) {
850
+ case "postgres":
851
+ database = new PostgresDatabase(config);
852
+ break;
853
+ case "mysql":
854
+ throw new Error("MySQL support not yet implemented");
855
+ case "sqlite":
856
+ throw new Error("SQLite support not yet implemented");
857
+ default:
858
+ throw new Error(`Unsupported database type: ${config.type}`);
859
+ }
860
+ this.databases.set(key, database);
861
+ if (this.defaultDatabaseKey === null) {
862
+ this.defaultDatabaseKey = key;
863
+ }
864
+ }
865
+ /**
866
+ * Set the default database
867
+ * @param key - Database key to set as default
868
+ */
869
+ setDefaultDatabase(key) {
870
+ if (!this.databases.has(key)) {
871
+ throw new Error(`Database '${key}' not found`);
872
+ }
873
+ this.defaultDatabaseKey = key;
874
+ }
875
+ /**
876
+ * Get a database by key
877
+ * @param key - Database key (optional, uses default if not provided)
878
+ */
879
+ getDatabase(key) {
880
+ const dbKey = key || this.defaultDatabaseKey;
881
+ if (!dbKey) {
882
+ throw new Error("No database registered");
883
+ }
884
+ const database = this.databases.get(dbKey);
885
+ if (!database) {
886
+ throw new Error(`Database '${dbKey}' not found`);
887
+ }
888
+ return database;
889
+ }
890
+ /**
891
+ * Check if a database is registered
892
+ * @param key - Database key
893
+ */
894
+ hasDatabase(key) {
895
+ return this.databases.has(key);
896
+ }
897
+ /**
898
+ * Get all registered database keys
899
+ */
900
+ getDatabaseKeys() {
901
+ return Array.from(this.databases.keys());
902
+ }
903
+ /**
904
+ * Remove a database connection
905
+ * @param key - Database key
906
+ */
907
+ async removeDatabase(key) {
908
+ const database = this.databases.get(key);
909
+ if (database) {
910
+ await database.disconnect();
911
+ this.databases.delete(key);
912
+ if (this.defaultDatabaseKey === key) {
913
+ this.defaultDatabaseKey = this.databases.size > 0 ? this.databases.keys().next().value || null : null;
914
+ }
915
+ }
916
+ }
917
+ /**
918
+ * Disconnect all databases
919
+ */
920
+ async disconnectAll() {
921
+ for (const database of this.databases.values()) {
922
+ await database.disconnect();
923
+ }
924
+ }
925
+ };
926
+ var sqlDatabaseManager = SqlDatabaseManager.getInstance();
927
+
928
+ // src/tool_lattice/sql/list_tables_sql.ts
929
+ function getDatabaseKeyFromConfig(config) {
930
+ const runConfig = config.configurable?.runConfig;
931
+ return runConfig?.databaseKey;
932
+ }
933
+ registerToolLattice(
934
+ "list_tables_sql",
935
+ {
936
+ name: "list_tables_sql",
937
+ description: "List all tables in the connected SQL database. Returns a comma-separated list of table names. Use this tool first to understand what tables are available before querying the database.",
938
+ needUserApprove: false,
939
+ schema: import_zod3.default.object({})
940
+ },
941
+ async (_input, config) => {
942
+ try {
943
+ const databaseKey = getDatabaseKeyFromConfig(config);
944
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
945
+ const tables = await database.listTables();
946
+ if (tables.length === 0) {
947
+ return "No tables found in the database.";
948
+ }
949
+ const tableNames = tables.map(
950
+ (t) => t.schema && t.schema !== "public" ? `${t.schema}.${t.name}` : t.name
951
+ );
952
+ return tableNames.join(", ");
953
+ } catch (error) {
954
+ return `Error listing tables: ${error instanceof Error ? error.message : String(error)}`;
955
+ }
956
+ }
957
+ );
958
+
959
+ // src/tool_lattice/sql/info_sql.ts
960
+ var import_zod4 = __toESM(require("zod"));
961
+ function getDatabaseKeyFromConfig2(config) {
962
+ const runConfig = config.configurable?.runConfig;
963
+ return runConfig?.databaseKey;
964
+ }
965
+ function formatTableSchema(schema) {
966
+ const lines = [];
967
+ lines.push(`
968
+ Table: ${schema.tableName}`);
969
+ lines.push("-".repeat(40));
970
+ lines.push("Columns:");
971
+ for (const col of schema.columns) {
972
+ const constraints = [];
973
+ if (col.isPrimaryKey) constraints.push("PRIMARY KEY");
974
+ if (col.isForeignKey && col.foreignKeyRef)
975
+ constraints.push(`FK -> ${col.foreignKeyRef}`);
976
+ if (!col.nullable) constraints.push("NOT NULL");
977
+ const constraintStr = constraints.length > 0 ? ` [${constraints.join(", ")}]` : "";
978
+ lines.push(` - ${col.name}: ${col.type}${constraintStr}`);
979
+ }
980
+ if (schema.sampleRows && schema.sampleRows.length > 0) {
981
+ lines.push("\nSample Rows (up to 3):");
982
+ for (const row of schema.sampleRows) {
983
+ const rowStr = Object.entries(row).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
984
+ lines.push(` ${rowStr}`);
985
+ }
986
+ }
987
+ return lines.join("\n");
988
+ }
989
+ registerToolLattice(
990
+ "info_sql",
991
+ {
992
+ name: "info_sql",
993
+ description: "Get detailed schema information for specified tables, including column names, types, constraints (primary keys, foreign keys), and sample rows. Input should be a comma-separated list of table names.",
994
+ needUserApprove: false,
995
+ schema: import_zod4.default.object({
996
+ tables: import_zod4.default.string().describe(
997
+ "Comma-separated list of table names to get information for. Example: 'users, orders, products'"
998
+ )
999
+ })
1000
+ },
1001
+ async ({
1002
+ tables
1003
+ }, config) => {
1004
+ try {
1005
+ const databaseKey = getDatabaseKeyFromConfig2(config);
1006
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
1007
+ const tableNames = tables.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
1008
+ if (tableNames.length === 0) {
1009
+ return "Error: No table names provided. Please provide a comma-separated list of table names.";
1010
+ }
1011
+ const schemas = await database.getTableInfo(tableNames);
1012
+ if (schemas.length === 0) {
1013
+ return `No schema information found for tables: ${tableNames.join(", ")}`;
1014
+ }
1015
+ const output = schemas.map(formatTableSchema).join("\n");
1016
+ return output;
1017
+ } catch (error) {
1018
+ return `Error getting table info: ${error instanceof Error ? error.message : String(error)}`;
1019
+ }
1020
+ }
1021
+ );
1022
+
1023
+ // src/tool_lattice/sql/query_sql.ts
1024
+ var import_zod5 = __toESM(require("zod"));
1025
+ function getDatabaseKeyFromConfig3(config) {
1026
+ const runConfig = config.configurable?.runConfig;
1027
+ return runConfig?.databaseKey;
1028
+ }
1029
+ function formatQueryResult(rows, fields) {
1030
+ if (rows.length === 0) {
1031
+ return "Query executed successfully. No rows returned.";
1032
+ }
1033
+ const lines = [];
1034
+ const columns = fields || Object.keys(rows[0]);
1035
+ lines.push(columns.join(" | "));
1036
+ lines.push("-".repeat(columns.join(" | ").length));
1037
+ const maxRows = 50;
1038
+ const displayRows = rows.slice(0, maxRows);
1039
+ for (const row of displayRows) {
1040
+ const values = columns.map((col) => {
1041
+ const val = row[col];
1042
+ if (val === null) return "NULL";
1043
+ if (typeof val === "object") return JSON.stringify(val);
1044
+ return String(val);
1045
+ });
1046
+ lines.push(values.join(" | "));
1047
+ }
1048
+ if (rows.length > maxRows) {
1049
+ lines.push(`
1050
+ ... (${rows.length - maxRows} more rows not shown)`);
1051
+ }
1052
+ lines.push(`
1053
+ Total rows: ${rows.length}`);
1054
+ return lines.join("\n");
1055
+ }
1056
+ registerToolLattice(
1057
+ "query_sql",
1058
+ {
1059
+ name: "query_sql",
1060
+ description: "Execute a SQL query against the database and return the results. Input should be a valid SQL query. Use this tool to retrieve data from the database. For complex queries, first use list_tables_sql and info_sql to understand the database schema.",
1061
+ needUserApprove: false,
1062
+ // SQL queries should require user approval for safety
1063
+ schema: import_zod5.default.object({
1064
+ query: import_zod5.default.string().describe(
1065
+ "The SQL query to execute. Should be a valid SELECT, INSERT, UPDATE, or DELETE statement."
1066
+ )
1067
+ })
1068
+ },
1069
+ async ({
1070
+ query
1071
+ }, config) => {
1072
+ try {
1073
+ const databaseKey = getDatabaseKeyFromConfig3(config);
1074
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
1075
+ const trimmedQuery = query.trim();
1076
+ if (!trimmedQuery) {
1077
+ return "Error: Empty query provided. Please provide a valid SQL query.";
1078
+ }
1079
+ const result = await database.executeQuery(trimmedQuery);
1080
+ return formatQueryResult(result.rows, result.fields);
1081
+ } catch (error) {
1082
+ return `Error executing query: ${error instanceof Error ? error.message : String(error)}`;
1083
+ }
1084
+ }
1085
+ );
1086
+
1087
+ // src/tool_lattice/sql/query_checker_sql.ts
1088
+ var import_zod6 = __toESM(require("zod"));
1089
+ function getDatabaseKeyFromConfig4(config) {
1090
+ const runConfig = config.configurable?.runConfig;
1091
+ return runConfig?.databaseKey;
1092
+ }
1093
+ var DANGEROUS_KEYWORDS = [
1094
+ "DROP",
1095
+ "TRUNCATE",
1096
+ "DELETE",
1097
+ "ALTER",
1098
+ "CREATE",
1099
+ "GRANT",
1100
+ "REVOKE"
1101
+ ];
1102
+ function checkSyntax(query) {
1103
+ const issues = [];
1104
+ const upperQuery = query.toUpperCase();
1105
+ let parenCount = 0;
1106
+ for (const char of query) {
1107
+ if (char === "(") parenCount++;
1108
+ if (char === ")") parenCount--;
1109
+ if (parenCount < 0) {
1110
+ issues.push("Unbalanced parentheses: found closing ) without matching (");
1111
+ break;
1112
+ }
1113
+ }
1114
+ if (parenCount > 0) {
1115
+ issues.push("Unbalanced parentheses: missing closing )");
1116
+ }
1117
+ const singleQuotes = (query.match(/'/g) || []).length;
1118
+ if (singleQuotes % 2 !== 0) {
1119
+ issues.push("Unbalanced single quotes");
1120
+ }
1121
+ if (upperQuery.includes("SELECT *") && upperQuery.includes("JOIN")) {
1122
+ issues.push(
1123
+ "Warning: SELECT * with JOIN may return duplicate column names. Consider specifying columns explicitly."
1124
+ );
1125
+ }
1126
+ if ((upperQuery.includes("UPDATE ") || upperQuery.includes("DELETE FROM ")) && !upperQuery.includes("WHERE ")) {
1127
+ issues.push(
1128
+ "Warning: UPDATE or DELETE without WHERE clause will affect all rows in the table."
1129
+ );
1130
+ }
1131
+ if (upperQuery.includes("GROUP BY") && !upperQuery.match(/\b(COUNT|SUM|AVG|MAX|MIN|ARRAY_AGG|STRING_AGG)\s*\(/i)) {
1132
+ issues.push(
1133
+ "Warning: GROUP BY used but no aggregate functions found. Make sure all non-aggregated columns are in GROUP BY."
1134
+ );
1135
+ }
1136
+ return issues;
1137
+ }
1138
+ function checkDangerousOperations(query) {
1139
+ const warnings = [];
1140
+ const upperQuery = query.toUpperCase();
1141
+ for (const keyword of DANGEROUS_KEYWORDS) {
1142
+ if (upperQuery.includes(keyword)) {
1143
+ warnings.push(
1144
+ `Warning: Query contains potentially dangerous operation: ${keyword}`
1145
+ );
1146
+ }
1147
+ }
1148
+ return warnings;
1149
+ }
1150
+ registerToolLattice(
1151
+ "query_checker_sql",
1152
+ {
1153
+ name: "query_checker_sql",
1154
+ description: "Check a SQL query for common issues before execution. This tool validates syntax, checks for dangerous operations, and provides suggestions for improvement. Use this before executing queries to ensure they are safe and correct.",
1155
+ needUserApprove: false,
1156
+ schema: import_zod6.default.object({
1157
+ query: import_zod6.default.string().describe("The SQL query to check and validate.")
1158
+ })
1159
+ },
1160
+ async ({
1161
+ query
1162
+ }, config) => {
1163
+ try {
1164
+ const trimmedQuery = query.trim();
1165
+ if (!trimmedQuery) {
1166
+ return "Error: Empty query provided. Please provide a SQL query to check.";
1167
+ }
1168
+ const results = [];
1169
+ results.push("SQL Query Check Results:");
1170
+ results.push("=".repeat(40));
1171
+ results.push(`
1172
+ Query:
1173
+ ${trimmedQuery}
1174
+ `);
1175
+ const syntaxIssues = checkSyntax(trimmedQuery);
1176
+ if (syntaxIssues.length > 0) {
1177
+ results.push("Syntax Issues:");
1178
+ for (const issue of syntaxIssues) {
1179
+ results.push(` - ${issue}`);
1180
+ }
1181
+ } else {
1182
+ results.push("Syntax: \u2713 No obvious syntax issues found");
1183
+ }
1184
+ const dangerWarnings = checkDangerousOperations(trimmedQuery);
1185
+ if (dangerWarnings.length > 0) {
1186
+ results.push("\nSafety Warnings:");
1187
+ for (const warning of dangerWarnings) {
1188
+ results.push(` - ${warning}`);
1189
+ }
1190
+ } else {
1191
+ results.push("Safety: \u2713 No dangerous operations detected");
1192
+ }
1193
+ try {
1194
+ const databaseKey = getDatabaseKeyFromConfig4(config);
1195
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
1196
+ const dbType = database.getDatabaseType();
1197
+ if (dbType === "postgres") {
1198
+ try {
1199
+ await database.executeQuery(`EXPLAIN ${trimmedQuery}`);
1200
+ results.push("Database Validation: \u2713 Query is valid against database schema");
1201
+ } catch (explainError) {
1202
+ results.push(
1203
+ `Database Validation: \u2717 ${explainError instanceof Error ? explainError.message : String(explainError)}`
1204
+ );
1205
+ }
1206
+ }
1207
+ } catch {
1208
+ results.push(
1209
+ "Database Validation: Skipped (no database connection available)"
1210
+ );
1211
+ }
1212
+ const hasErrors = syntaxIssues.some((i) => !i.startsWith("Warning:")) || dangerWarnings.length > 0;
1213
+ results.push("\n" + "=".repeat(40));
1214
+ if (hasErrors) {
1215
+ results.push(
1216
+ "Overall: \u26A0\uFE0F Query has potential issues. Review warnings before execution."
1217
+ );
1218
+ } else {
1219
+ results.push("Overall: \u2713 Query appears to be safe to execute.");
1220
+ }
1221
+ return results.join("\n");
1222
+ } catch (error) {
1223
+ return `Error checking query: ${error instanceof Error ? error.message : String(error)}`;
1224
+ }
1225
+ }
1226
+ );
1227
+
683
1228
  // src/agent_lattice/types.ts
684
1229
  var import_protocols = require("@axiom-lattice/protocols");
685
1230
 
@@ -764,7 +1309,7 @@ var memory = new import_langgraph2.MemorySaver();
764
1309
  registerCheckpointSaver("default", memory);
765
1310
 
766
1311
  // src/agent_lattice/builders/state.ts
767
- var import_zod3 = require("@langchain/langgraph/zod");
1312
+ var import_zod7 = require("@langchain/langgraph/zod");
768
1313
  var import_langgraph3 = require("@langchain/langgraph");
769
1314
  var createReactAgentSchema = (schema) => {
770
1315
  return schema ? import_langgraph3.MessagesZodState.extend(schema.shape) : void 0;
@@ -804,7 +1349,7 @@ var import_langchain6 = require("langchain");
804
1349
  var import_langchain2 = require("langchain");
805
1350
  var import_langgraph4 = require("@langchain/langgraph");
806
1351
  var import_v3 = require("zod/v3");
807
- var import_zod4 = require("@langchain/langgraph/zod");
1352
+ var import_zod8 = require("@langchain/langgraph/zod");
808
1353
 
809
1354
  // src/deep_agent_new/backends/utils.ts
810
1355
  var import_micromatch = __toESM(require("micromatch"));
@@ -1172,7 +1717,7 @@ function fileDataReducer(left, right) {
1172
1717
  return result;
1173
1718
  }
1174
1719
  var FilesystemStateSchema = import_v3.z.object({
1175
- files: (0, import_zod4.withLangGraph)(
1720
+ files: (0, import_zod8.withLangGraph)(
1176
1721
  import_v3.z.record(import_v3.z.string(), FileDataSchema).default({}),
1177
1722
  {
1178
1723
  reducer: {
@@ -2295,7 +2840,7 @@ var SUPPORTS_NOFOLLOW = fsSync.constants.O_NOFOLLOW !== void 0;
2295
2840
 
2296
2841
  // src/deep_agent_new/middleware/todos.ts
2297
2842
  var import_langgraph8 = require("@langchain/langgraph");
2298
- var import_zod5 = require("zod");
2843
+ var import_zod9 = require("zod");
2299
2844
  var import_langchain5 = require("langchain");
2300
2845
  var WRITE_TODOS_DESCRIPTION = `Use this tool to create and manage a structured task list for your current work session. This helps you track progress, organize complex tasks, and demonstrate thoroughness to the user.
2301
2846
  It also helps the user understand the progress of the task and overall progress of their requests.
@@ -2523,12 +3068,12 @@ Writing todos takes time and tokens, use it when it is helpful for managing comp
2523
3068
  ## Important To-Do List Usage Notes to Remember
2524
3069
  - The \`write_todos\` tool should never be called multiple times in parallel.
2525
3070
  - Don't be afraid to revise the To-Do list as you go. New information may reveal new tasks that need to be done, or old tasks that are irrelevant.`;
2526
- var TodoStatus = import_zod5.z.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
2527
- var TodoSchema = import_zod5.z.object({
2528
- content: import_zod5.z.string().describe("Content of the todo item"),
3071
+ var TodoStatus = import_zod9.z.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
3072
+ var TodoSchema = import_zod9.z.object({
3073
+ content: import_zod9.z.string().describe("Content of the todo item"),
2529
3074
  status: TodoStatus
2530
3075
  });
2531
- var stateSchema = import_zod5.z.object({ todos: import_zod5.z.array(TodoSchema).default([]) });
3076
+ var stateSchema = import_zod9.z.object({ todos: import_zod9.z.array(TodoSchema).default([]) });
2532
3077
  function todoListMiddleware(options) {
2533
3078
  const writeTodos = (0, import_langchain5.tool)(
2534
3079
  ({ todos }, config) => {
@@ -2547,8 +3092,8 @@ function todoListMiddleware(options) {
2547
3092
  {
2548
3093
  name: "write_todos",
2549
3094
  description: options?.toolDescription ?? WRITE_TODOS_DESCRIPTION,
2550
- schema: import_zod5.z.object({
2551
- todos: import_zod5.z.array(TodoSchema).describe("List of todo items to update")
3095
+ schema: import_zod9.z.object({
3096
+ todos: import_zod9.z.array(TodoSchema).describe("List of todo items to update")
2552
3097
  })
2553
3098
  }
2554
3099
  );
@@ -3275,6 +3820,986 @@ var getChunkBuffer = (key) => ChunkBufferLatticeManager.getInstance().get(key);
3275
3820
  var registerChunkBuffer = (key, buffer) => ChunkBufferLatticeManager.getInstance().register(key, buffer);
3276
3821
  var hasChunkBuffer = (key) => ChunkBufferLatticeManager.getInstance().has(key);
3277
3822
 
3823
+ // src/schedule_lattice/ScheduleLatticeManager.ts
3824
+ var import_protocols7 = require("@axiom-lattice/protocols");
3825
+
3826
+ // src/schedule_lattice/DefaultScheduleClient.ts
3827
+ var import_protocols6 = require("@axiom-lattice/protocols");
3828
+
3829
+ // src/schedule_lattice/MemoryScheduleStorage.ts
3830
+ var import_protocols5 = require("@axiom-lattice/protocols");
3831
+ var MemoryScheduleStorage = class {
3832
+ constructor() {
3833
+ this.tasks = /* @__PURE__ */ new Map();
3834
+ }
3835
+ /**
3836
+ * Save a new task
3837
+ */
3838
+ async save(task) {
3839
+ this.tasks.set(task.taskId, { ...task });
3840
+ }
3841
+ /**
3842
+ * Get task by ID
3843
+ */
3844
+ async get(taskId) {
3845
+ const task = this.tasks.get(taskId);
3846
+ return task ? { ...task } : null;
3847
+ }
3848
+ /**
3849
+ * Update task
3850
+ */
3851
+ async update(taskId, updates) {
3852
+ const task = this.tasks.get(taskId);
3853
+ if (task) {
3854
+ this.tasks.set(taskId, {
3855
+ ...task,
3856
+ ...updates,
3857
+ updatedAt: Date.now()
3858
+ });
3859
+ }
3860
+ }
3861
+ /**
3862
+ * Delete task
3863
+ */
3864
+ async delete(taskId) {
3865
+ this.tasks.delete(taskId);
3866
+ }
3867
+ /**
3868
+ * Get all active tasks (pending or paused)
3869
+ */
3870
+ async getActiveTasks() {
3871
+ const result = [];
3872
+ for (const task of this.tasks.values()) {
3873
+ if (task.status === import_protocols5.ScheduledTaskStatus.PENDING || task.status === import_protocols5.ScheduledTaskStatus.PAUSED) {
3874
+ result.push({ ...task });
3875
+ }
3876
+ }
3877
+ return result;
3878
+ }
3879
+ /**
3880
+ * Get tasks by type
3881
+ */
3882
+ async getTasksByType(taskType) {
3883
+ const result = [];
3884
+ for (const task of this.tasks.values()) {
3885
+ if (task.taskType === taskType) {
3886
+ result.push({ ...task });
3887
+ }
3888
+ }
3889
+ return result;
3890
+ }
3891
+ /**
3892
+ * Get tasks by status
3893
+ */
3894
+ async getTasksByStatus(status) {
3895
+ const result = [];
3896
+ for (const task of this.tasks.values()) {
3897
+ if (task.status === status) {
3898
+ result.push({ ...task });
3899
+ }
3900
+ }
3901
+ return result;
3902
+ }
3903
+ /**
3904
+ * Get tasks by execution type
3905
+ */
3906
+ async getTasksByExecutionType(executionType) {
3907
+ const result = [];
3908
+ for (const task of this.tasks.values()) {
3909
+ if (task.executionType === executionType) {
3910
+ result.push({ ...task });
3911
+ }
3912
+ }
3913
+ return result;
3914
+ }
3915
+ /**
3916
+ * Get tasks by assistant ID
3917
+ */
3918
+ async getTasksByAssistantId(assistantId) {
3919
+ const result = [];
3920
+ for (const task of this.tasks.values()) {
3921
+ if (task.assistantId === assistantId) {
3922
+ result.push({ ...task });
3923
+ }
3924
+ }
3925
+ return result;
3926
+ }
3927
+ /**
3928
+ * Get tasks by thread ID
3929
+ */
3930
+ async getTasksByThreadId(threadId) {
3931
+ const result = [];
3932
+ for (const task of this.tasks.values()) {
3933
+ if (task.threadId === threadId) {
3934
+ result.push({ ...task });
3935
+ }
3936
+ }
3937
+ return result;
3938
+ }
3939
+ /**
3940
+ * Get all tasks with optional filters
3941
+ */
3942
+ async getAllTasks(filters) {
3943
+ let result = [];
3944
+ for (const task of this.tasks.values()) {
3945
+ let match = true;
3946
+ if (filters?.status !== void 0 && task.status !== filters.status) {
3947
+ match = false;
3948
+ }
3949
+ if (filters?.executionType !== void 0 && task.executionType !== filters.executionType) {
3950
+ match = false;
3951
+ }
3952
+ if (filters?.taskType !== void 0 && task.taskType !== filters.taskType) {
3953
+ match = false;
3954
+ }
3955
+ if (filters?.assistantId !== void 0 && task.assistantId !== filters.assistantId) {
3956
+ match = false;
3957
+ }
3958
+ if (filters?.threadId !== void 0 && task.threadId !== filters.threadId) {
3959
+ match = false;
3960
+ }
3961
+ if (match) {
3962
+ result.push({ ...task });
3963
+ }
3964
+ }
3965
+ result.sort((a, b) => b.createdAt - a.createdAt);
3966
+ const offset = filters?.offset || 0;
3967
+ const limit = filters?.limit;
3968
+ if (limit !== void 0) {
3969
+ result = result.slice(offset, offset + limit);
3970
+ } else if (offset > 0) {
3971
+ result = result.slice(offset);
3972
+ }
3973
+ return result;
3974
+ }
3975
+ /**
3976
+ * Count tasks with optional filters
3977
+ */
3978
+ async countTasks(filters) {
3979
+ let count = 0;
3980
+ for (const task of this.tasks.values()) {
3981
+ let match = true;
3982
+ if (filters?.status !== void 0 && task.status !== filters.status) {
3983
+ match = false;
3984
+ }
3985
+ if (filters?.executionType !== void 0 && task.executionType !== filters.executionType) {
3986
+ match = false;
3987
+ }
3988
+ if (filters?.taskType !== void 0 && task.taskType !== filters.taskType) {
3989
+ match = false;
3990
+ }
3991
+ if (filters?.assistantId !== void 0 && task.assistantId !== filters.assistantId) {
3992
+ match = false;
3993
+ }
3994
+ if (filters?.threadId !== void 0 && task.threadId !== filters.threadId) {
3995
+ match = false;
3996
+ }
3997
+ if (match) {
3998
+ count++;
3999
+ }
4000
+ }
4001
+ return count;
4002
+ }
4003
+ /**
4004
+ * Delete completed/cancelled tasks older than specified time
4005
+ */
4006
+ async deleteOldTasks(olderThanMs) {
4007
+ const cutoff = Date.now() - olderThanMs;
4008
+ let deleted = 0;
4009
+ for (const [taskId, task] of this.tasks.entries()) {
4010
+ if ((task.status === import_protocols5.ScheduledTaskStatus.COMPLETED || task.status === import_protocols5.ScheduledTaskStatus.CANCELLED || task.status === import_protocols5.ScheduledTaskStatus.FAILED) && task.updatedAt < cutoff) {
4011
+ this.tasks.delete(taskId);
4012
+ deleted++;
4013
+ }
4014
+ }
4015
+ return deleted;
4016
+ }
4017
+ /**
4018
+ * Clear all tasks (useful for testing)
4019
+ */
4020
+ clear() {
4021
+ this.tasks.clear();
4022
+ }
4023
+ /**
4024
+ * Get total task count (useful for debugging)
4025
+ */
4026
+ size() {
4027
+ return this.tasks.size;
4028
+ }
4029
+ };
4030
+
4031
+ // src/schedule_lattice/CronParser.ts
4032
+ function parseCronExpression(expression) {
4033
+ const parts = expression.trim().split(/\s+/);
4034
+ if (parts.length !== 5) {
4035
+ throw new Error(
4036
+ `Invalid cron expression: expected 5 fields, got ${parts.length}`
4037
+ );
4038
+ }
4039
+ return {
4040
+ minute: parseField(parts[0], 0, 59),
4041
+ hour: parseField(parts[1], 0, 23),
4042
+ dayOfMonth: parseField(parts[2], 1, 31),
4043
+ month: parseField(parts[3], 1, 12),
4044
+ dayOfWeek: parseField(parts[4], 0, 7).map((d) => d === 7 ? 0 : d)
4045
+ // Normalize Sunday
4046
+ };
4047
+ }
4048
+ function parseField(field, min, max) {
4049
+ const values = /* @__PURE__ */ new Set();
4050
+ const segments = field.split(",");
4051
+ for (const segment of segments) {
4052
+ const [range, stepStr] = segment.split("/");
4053
+ const step = stepStr ? parseInt(stepStr, 10) : 1;
4054
+ if (isNaN(step) || step < 1) {
4055
+ throw new Error(`Invalid step value: ${stepStr}`);
4056
+ }
4057
+ let rangeStart;
4058
+ let rangeEnd;
4059
+ if (range === "*") {
4060
+ rangeStart = min;
4061
+ rangeEnd = max;
4062
+ } else if (range.includes("-")) {
4063
+ const [startStr, endStr] = range.split("-");
4064
+ rangeStart = parseInt(startStr, 10);
4065
+ rangeEnd = parseInt(endStr, 10);
4066
+ if (isNaN(rangeStart) || isNaN(rangeEnd)) {
4067
+ throw new Error(`Invalid range: ${range}`);
4068
+ }
4069
+ } else {
4070
+ const value = parseInt(range, 10);
4071
+ if (isNaN(value)) {
4072
+ throw new Error(`Invalid value: ${range}`);
4073
+ }
4074
+ rangeStart = value;
4075
+ rangeEnd = value;
4076
+ }
4077
+ if (rangeStart < min || rangeEnd > max || rangeStart > rangeEnd) {
4078
+ throw new Error(`Value out of range: ${range} (expected ${min}-${max})`);
4079
+ }
4080
+ for (let i = rangeStart; i <= rangeEnd; i += step) {
4081
+ values.add(i);
4082
+ }
4083
+ }
4084
+ return Array.from(values).sort((a, b) => a - b);
4085
+ }
4086
+ function getNextCronTime(expression, after = /* @__PURE__ */ new Date(), timezone) {
4087
+ const fields = parseCronExpression(expression);
4088
+ const next = new Date(after.getTime());
4089
+ next.setSeconds(0, 0);
4090
+ next.setMinutes(next.getMinutes() + 1);
4091
+ const maxIterations = 366 * 24 * 60;
4092
+ let iterations = 0;
4093
+ while (iterations < maxIterations) {
4094
+ iterations++;
4095
+ const month = next.getMonth() + 1;
4096
+ if (!fields.month.includes(month)) {
4097
+ const nextMonth = fields.month.find((m) => m > month);
4098
+ if (nextMonth !== void 0) {
4099
+ next.setMonth(nextMonth - 1, 1);
4100
+ } else {
4101
+ next.setFullYear(next.getFullYear() + 1);
4102
+ next.setMonth(fields.month[0] - 1, 1);
4103
+ }
4104
+ next.setHours(fields.hour[0], fields.minute[0], 0, 0);
4105
+ continue;
4106
+ }
4107
+ const dayOfMonth = next.getDate();
4108
+ const maxDayOfMonth = new Date(
4109
+ next.getFullYear(),
4110
+ next.getMonth() + 1,
4111
+ 0
4112
+ ).getDate();
4113
+ const dayOfWeek = next.getDay();
4114
+ const dayOfMonthMatch = fields.dayOfMonth.includes(dayOfMonth);
4115
+ const dayOfWeekMatch = fields.dayOfWeek.includes(dayOfWeek);
4116
+ const dayOfMonthWildcard = fields.dayOfMonth.length === 31 && fields.dayOfMonth[0] === 1 && fields.dayOfMonth[30] === 31;
4117
+ const dayOfWeekWildcard = fields.dayOfWeek.length >= 7 || fields.dayOfWeek.length === 1 && fields.dayOfWeek.includes(0);
4118
+ let dayMatch;
4119
+ if (dayOfMonthWildcard && dayOfWeekWildcard) {
4120
+ dayMatch = true;
4121
+ } else if (dayOfMonthWildcard) {
4122
+ dayMatch = dayOfWeekMatch;
4123
+ } else if (dayOfWeekWildcard) {
4124
+ dayMatch = dayOfMonthMatch;
4125
+ } else {
4126
+ dayMatch = dayOfMonthMatch || dayOfWeekMatch;
4127
+ }
4128
+ if (!dayMatch || dayOfMonth > maxDayOfMonth) {
4129
+ next.setDate(next.getDate() + 1);
4130
+ next.setHours(fields.hour[0], fields.minute[0], 0, 0);
4131
+ continue;
4132
+ }
4133
+ const hour = next.getHours();
4134
+ if (!fields.hour.includes(hour)) {
4135
+ const nextHour = fields.hour.find((h) => h > hour);
4136
+ if (nextHour !== void 0) {
4137
+ next.setHours(nextHour, fields.minute[0], 0, 0);
4138
+ } else {
4139
+ next.setDate(next.getDate() + 1);
4140
+ next.setHours(fields.hour[0], fields.minute[0], 0, 0);
4141
+ }
4142
+ continue;
4143
+ }
4144
+ const minute = next.getMinutes();
4145
+ if (!fields.minute.includes(minute)) {
4146
+ const nextMinute = fields.minute.find((m) => m > minute);
4147
+ if (nextMinute !== void 0) {
4148
+ next.setMinutes(nextMinute, 0, 0);
4149
+ } else {
4150
+ next.setHours(next.getHours() + 1, fields.minute[0], 0, 0);
4151
+ }
4152
+ continue;
4153
+ }
4154
+ return next;
4155
+ }
4156
+ throw new Error("Could not find next cron time within 1 year");
4157
+ }
4158
+ function isValidCronExpression(expression) {
4159
+ try {
4160
+ parseCronExpression(expression);
4161
+ return true;
4162
+ } catch {
4163
+ return false;
4164
+ }
4165
+ }
4166
+ function describeCronExpression(expression) {
4167
+ const fields = parseCronExpression(expression);
4168
+ const parts = [];
4169
+ if (fields.minute.length === 60) {
4170
+ parts.push("every minute");
4171
+ } else if (fields.minute.length === 1) {
4172
+ parts.push(`at minute ${fields.minute[0]}`);
4173
+ } else {
4174
+ parts.push(`at minutes ${fields.minute.join(", ")}`);
4175
+ }
4176
+ if (fields.hour.length === 24) {
4177
+ parts.push("of every hour");
4178
+ } else if (fields.hour.length === 1) {
4179
+ parts.push(`of hour ${fields.hour[0]}`);
4180
+ } else {
4181
+ parts.push(`of hours ${fields.hour.join(", ")}`);
4182
+ }
4183
+ if (fields.dayOfMonth.length < 31) {
4184
+ if (fields.dayOfMonth.length === 1) {
4185
+ parts.push(`on day ${fields.dayOfMonth[0]}`);
4186
+ } else {
4187
+ parts.push(`on days ${fields.dayOfMonth.join(", ")}`);
4188
+ }
4189
+ }
4190
+ const monthNames = [
4191
+ "",
4192
+ "Jan",
4193
+ "Feb",
4194
+ "Mar",
4195
+ "Apr",
4196
+ "May",
4197
+ "Jun",
4198
+ "Jul",
4199
+ "Aug",
4200
+ "Sep",
4201
+ "Oct",
4202
+ "Nov",
4203
+ "Dec"
4204
+ ];
4205
+ if (fields.month.length < 12) {
4206
+ const months = fields.month.map((m) => monthNames[m]);
4207
+ parts.push(`in ${months.join(", ")}`);
4208
+ }
4209
+ const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
4210
+ const uniqueDays = [...new Set(fields.dayOfWeek)];
4211
+ if (uniqueDays.length < 7) {
4212
+ const days = uniqueDays.map((d) => dayNames[d]);
4213
+ parts.push(`on ${days.join(", ")}`);
4214
+ }
4215
+ return parts.join(" ");
4216
+ }
4217
+
4218
+ // src/schedule_lattice/DefaultScheduleClient.ts
4219
+ var _DefaultScheduleClient = class _DefaultScheduleClient {
4220
+ constructor(storage) {
4221
+ this.handlers = /* @__PURE__ */ new Map();
4222
+ this.timers = /* @__PURE__ */ new Map();
4223
+ this.storage = storage || new MemoryScheduleStorage();
4224
+ }
4225
+ /**
4226
+ * Get the singleton instance of DefaultScheduleClient
4227
+ */
4228
+ static getInstance(storage) {
4229
+ if (!_DefaultScheduleClient.instance) {
4230
+ _DefaultScheduleClient.instance = new _DefaultScheduleClient(storage);
4231
+ }
4232
+ return _DefaultScheduleClient.instance;
4233
+ }
4234
+ /**
4235
+ * Reset the singleton instance (useful for testing)
4236
+ */
4237
+ static resetInstance() {
4238
+ if (_DefaultScheduleClient.instance) {
4239
+ _DefaultScheduleClient.instance.cancelAll();
4240
+ _DefaultScheduleClient.instance = null;
4241
+ }
4242
+ }
4243
+ // ===== Handler Registration =====
4244
+ registerHandler(taskType, handler) {
4245
+ this.handlers.set(taskType, handler);
4246
+ console.log(`[Scheduler] Handler registered for task type: ${taskType}`);
4247
+ }
4248
+ unregisterHandler(taskType) {
4249
+ const result = this.handlers.delete(taskType);
4250
+ if (result) {
4251
+ console.log(
4252
+ `[Scheduler] Handler unregistered for task type: ${taskType}`
4253
+ );
4254
+ }
4255
+ return result;
4256
+ }
4257
+ hasHandler(taskType) {
4258
+ return this.handlers.has(taskType);
4259
+ }
4260
+ getHandlerTypes() {
4261
+ return Array.from(this.handlers.keys());
4262
+ }
4263
+ // ===== One-time Task Scheduling =====
4264
+ async scheduleOnce(taskId, taskType, payload, options) {
4265
+ if (!this.handlers.has(taskType)) {
4266
+ console.error(
4267
+ `[Scheduler] No handler registered for task type: ${taskType}`
4268
+ );
4269
+ return false;
4270
+ }
4271
+ let executeAt;
4272
+ if (options.executeAt !== void 0) {
4273
+ executeAt = options.executeAt;
4274
+ } else if (options.delayMs !== void 0) {
4275
+ executeAt = Date.now() + options.delayMs;
4276
+ } else {
4277
+ console.error("[Scheduler] Either executeAt or delayMs must be provided");
4278
+ return false;
4279
+ }
4280
+ if (await this.has(taskId)) {
4281
+ await this.cancel(taskId);
4282
+ }
4283
+ const now = Date.now();
4284
+ const task = {
4285
+ taskId,
4286
+ taskType,
4287
+ payload,
4288
+ assistantId: options.assistantId,
4289
+ threadId: options.threadId,
4290
+ executionType: import_protocols6.ScheduleExecutionType.ONCE,
4291
+ executeAt,
4292
+ delayMs: options.delayMs,
4293
+ status: import_protocols6.ScheduledTaskStatus.PENDING,
4294
+ runCount: 0,
4295
+ retryCount: 0,
4296
+ maxRetries: options.maxRetries ?? 0,
4297
+ createdAt: now,
4298
+ updatedAt: now,
4299
+ metadata: options.metadata
4300
+ };
4301
+ await this.storage.save(task);
4302
+ this.scheduleTimer(task);
4303
+ console.log(
4304
+ `[Scheduler] One-time task scheduled: ${taskId}, executes at ${new Date(
4305
+ executeAt
4306
+ ).toISOString()}`
4307
+ );
4308
+ return true;
4309
+ }
4310
+ // ===== Cron Task Scheduling =====
4311
+ async scheduleCron(taskId, taskType, payload, options) {
4312
+ if (!this.handlers.has(taskType)) {
4313
+ console.error(
4314
+ `[Scheduler] No handler registered for task type: ${taskType}`
4315
+ );
4316
+ return false;
4317
+ }
4318
+ if (!isValidCronExpression(options.cronExpression)) {
4319
+ console.error(
4320
+ `[Scheduler] Invalid cron expression: ${options.cronExpression}`
4321
+ );
4322
+ return false;
4323
+ }
4324
+ if (await this.has(taskId)) {
4325
+ await this.cancel(taskId);
4326
+ }
4327
+ const now = Date.now();
4328
+ const nextRunAt = getNextCronTime(options.cronExpression, new Date(now));
4329
+ const task = {
4330
+ taskId,
4331
+ taskType,
4332
+ payload,
4333
+ assistantId: options.assistantId,
4334
+ threadId: options.threadId,
4335
+ executionType: import_protocols6.ScheduleExecutionType.CRON,
4336
+ cronExpression: options.cronExpression,
4337
+ timezone: options.timezone,
4338
+ nextRunAt: nextRunAt.getTime(),
4339
+ status: import_protocols6.ScheduledTaskStatus.PENDING,
4340
+ runCount: 0,
4341
+ maxRuns: options.maxRuns,
4342
+ retryCount: 0,
4343
+ maxRetries: options.maxRetries ?? 0,
4344
+ createdAt: now,
4345
+ updatedAt: now,
4346
+ expiresAt: options.expiresAt,
4347
+ metadata: options.metadata
4348
+ };
4349
+ await this.storage.save(task);
4350
+ this.scheduleTimer(task);
4351
+ console.log(
4352
+ `[Scheduler] Cron task scheduled: ${taskId}, expression: ${options.cronExpression}, next run: ${nextRunAt.toISOString()}`
4353
+ );
4354
+ return true;
4355
+ }
4356
+ // ===== Task Management =====
4357
+ async cancel(taskId) {
4358
+ const timer = this.timers.get(taskId);
4359
+ if (timer) {
4360
+ clearTimeout(timer.timerId);
4361
+ this.timers.delete(taskId);
4362
+ }
4363
+ const task = await this.storage.get(taskId);
4364
+ if (task) {
4365
+ await this.storage.update(taskId, {
4366
+ status: import_protocols6.ScheduledTaskStatus.CANCELLED
4367
+ });
4368
+ console.log(`[Scheduler] Task cancelled: ${taskId}`);
4369
+ return true;
4370
+ }
4371
+ return false;
4372
+ }
4373
+ async pause(taskId) {
4374
+ const task = await this.storage.get(taskId);
4375
+ if (!task || task.executionType !== import_protocols6.ScheduleExecutionType.CRON) {
4376
+ console.error(`[Scheduler] Can only pause CRON tasks: ${taskId}`);
4377
+ return false;
4378
+ }
4379
+ if (task.status !== import_protocols6.ScheduledTaskStatus.PENDING) {
4380
+ console.error(`[Scheduler] Can only pause PENDING tasks: ${taskId}`);
4381
+ return false;
4382
+ }
4383
+ const timer = this.timers.get(taskId);
4384
+ if (timer) {
4385
+ clearTimeout(timer.timerId);
4386
+ this.timers.delete(taskId);
4387
+ }
4388
+ await this.storage.update(taskId, {
4389
+ status: import_protocols6.ScheduledTaskStatus.PAUSED
4390
+ });
4391
+ console.log(`[Scheduler] Task paused: ${taskId}`);
4392
+ return true;
4393
+ }
4394
+ async resume(taskId) {
4395
+ const task = await this.storage.get(taskId);
4396
+ if (!task || task.executionType !== import_protocols6.ScheduleExecutionType.CRON) {
4397
+ console.error(`[Scheduler] Can only resume CRON tasks: ${taskId}`);
4398
+ return false;
4399
+ }
4400
+ if (task.status !== import_protocols6.ScheduledTaskStatus.PAUSED) {
4401
+ console.error(`[Scheduler] Can only resume PAUSED tasks: ${taskId}`);
4402
+ return false;
4403
+ }
4404
+ const nextRunAt = getNextCronTime(task.cronExpression);
4405
+ await this.storage.update(taskId, {
4406
+ status: import_protocols6.ScheduledTaskStatus.PENDING,
4407
+ nextRunAt: nextRunAt.getTime()
4408
+ });
4409
+ const updatedTask = await this.storage.get(taskId);
4410
+ if (updatedTask) {
4411
+ this.scheduleTimer(updatedTask);
4412
+ }
4413
+ console.log(`[Scheduler] Task resumed: ${taskId}`);
4414
+ return true;
4415
+ }
4416
+ async has(taskId) {
4417
+ const task = await this.storage.get(taskId);
4418
+ return task !== null;
4419
+ }
4420
+ async getTask(taskId) {
4421
+ return this.storage.get(taskId);
4422
+ }
4423
+ async getRemainingTime(taskId) {
4424
+ const task = await this.storage.get(taskId);
4425
+ if (!task) {
4426
+ return -1;
4427
+ }
4428
+ const targetTime = task.executionType === import_protocols6.ScheduleExecutionType.CRON ? task.nextRunAt : task.executeAt;
4429
+ if (targetTime === void 0) {
4430
+ return -1;
4431
+ }
4432
+ return Math.max(0, targetTime - Date.now());
4433
+ }
4434
+ async getActiveTaskCount() {
4435
+ const tasks = await this.storage.getActiveTasks();
4436
+ return tasks.length;
4437
+ }
4438
+ async getActiveTaskIds() {
4439
+ const tasks = await this.storage.getActiveTasks();
4440
+ return tasks.map((t) => t.taskId);
4441
+ }
4442
+ async cancelAll() {
4443
+ for (const timer of this.timers.values()) {
4444
+ clearTimeout(timer.timerId);
4445
+ }
4446
+ this.timers.clear();
4447
+ const activeTasks = await this.storage.getActiveTasks();
4448
+ for (const task of activeTasks) {
4449
+ await this.storage.update(task.taskId, {
4450
+ status: import_protocols6.ScheduledTaskStatus.CANCELLED
4451
+ });
4452
+ }
4453
+ console.log(`[Scheduler] All tasks cancelled`);
4454
+ }
4455
+ // ===== Recovery =====
4456
+ async restore() {
4457
+ const activeTasks = await this.storage.getActiveTasks();
4458
+ let restored = 0;
4459
+ for (const task of activeTasks) {
4460
+ if (!this.handlers.has(task.taskType)) {
4461
+ console.warn(
4462
+ `[Scheduler] No handler for task type ${task.taskType}, skipping restore for task ${task.taskId}`
4463
+ );
4464
+ continue;
4465
+ }
4466
+ if (task.status === import_protocols6.ScheduledTaskStatus.PAUSED) {
4467
+ continue;
4468
+ }
4469
+ if (task.executionType === import_protocols6.ScheduleExecutionType.ONCE) {
4470
+ if (task.executeAt && task.executeAt <= Date.now()) {
4471
+ console.log(
4472
+ `[Scheduler] Executing overdue one-time task: ${task.taskId}`
4473
+ );
4474
+ this.executeTask(task);
4475
+ } else {
4476
+ this.scheduleTimer(task);
4477
+ }
4478
+ } else if (task.executionType === import_protocols6.ScheduleExecutionType.CRON) {
4479
+ const nextRunAt = getNextCronTime(task.cronExpression);
4480
+ await this.storage.update(task.taskId, {
4481
+ nextRunAt: nextRunAt.getTime()
4482
+ });
4483
+ const updatedTask = await this.storage.get(task.taskId);
4484
+ if (updatedTask) {
4485
+ this.scheduleTimer(updatedTask);
4486
+ }
4487
+ }
4488
+ restored++;
4489
+ }
4490
+ console.log(`[Scheduler] Restored ${restored} tasks`);
4491
+ return restored;
4492
+ }
4493
+ // ===== Storage =====
4494
+ setStorage(storage) {
4495
+ this.storage = storage;
4496
+ }
4497
+ getStorage() {
4498
+ return this.storage;
4499
+ }
4500
+ // ===== Private Methods =====
4501
+ scheduleTimer(task) {
4502
+ const targetTime = task.executionType === import_protocols6.ScheduleExecutionType.CRON ? task.nextRunAt : task.executeAt;
4503
+ if (targetTime === void 0) {
4504
+ console.error(`[Scheduler] No execution time for task: ${task.taskId}`);
4505
+ return;
4506
+ }
4507
+ const delay = Math.max(0, targetTime - Date.now());
4508
+ const timerId = setTimeout(() => {
4509
+ this.executeTask(task);
4510
+ }, delay);
4511
+ this.timers.set(task.taskId, {
4512
+ timerId,
4513
+ taskId: task.taskId
4514
+ });
4515
+ }
4516
+ async executeTask(task) {
4517
+ const handler = this.handlers.get(task.taskType);
4518
+ if (!handler) {
4519
+ console.error(
4520
+ `[Scheduler] No handler for task type: ${task.taskType}, task: ${task.taskId}`
4521
+ );
4522
+ await this.storage.update(task.taskId, {
4523
+ status: import_protocols6.ScheduledTaskStatus.FAILED,
4524
+ lastError: `No handler registered for task type: ${task.taskType}`
4525
+ });
4526
+ return;
4527
+ }
4528
+ await this.storage.update(task.taskId, {
4529
+ status: import_protocols6.ScheduledTaskStatus.RUNNING
4530
+ });
4531
+ console.log(`[Scheduler] Executing task: ${task.taskId}`);
4532
+ try {
4533
+ const latestTask = await this.storage.get(task.taskId);
4534
+ if (!latestTask) {
4535
+ console.error(`[Scheduler] Task not found: ${task.taskId}`);
4536
+ return;
4537
+ }
4538
+ await handler(latestTask.payload, latestTask);
4539
+ const newRunCount = latestTask.runCount + 1;
4540
+ console.log(`[Scheduler] Task completed: ${task.taskId}`);
4541
+ if (task.executionType === import_protocols6.ScheduleExecutionType.ONCE) {
4542
+ await this.storage.update(task.taskId, {
4543
+ status: import_protocols6.ScheduledTaskStatus.COMPLETED,
4544
+ runCount: newRunCount,
4545
+ lastRunAt: Date.now()
4546
+ });
4547
+ this.timers.delete(task.taskId);
4548
+ } else if (task.executionType === import_protocols6.ScheduleExecutionType.CRON) {
4549
+ if (task.maxRuns !== void 0 && newRunCount >= task.maxRuns) {
4550
+ await this.storage.update(task.taskId, {
4551
+ status: import_protocols6.ScheduledTaskStatus.COMPLETED,
4552
+ runCount: newRunCount,
4553
+ lastRunAt: Date.now()
4554
+ });
4555
+ this.timers.delete(task.taskId);
4556
+ console.log(
4557
+ `[Scheduler] Cron task completed (max runs): ${task.taskId}`
4558
+ );
4559
+ return;
4560
+ }
4561
+ if (task.expiresAt !== void 0 && Date.now() >= task.expiresAt) {
4562
+ await this.storage.update(task.taskId, {
4563
+ status: import_protocols6.ScheduledTaskStatus.COMPLETED,
4564
+ runCount: newRunCount,
4565
+ lastRunAt: Date.now()
4566
+ });
4567
+ this.timers.delete(task.taskId);
4568
+ console.log(
4569
+ `[Scheduler] Cron task completed (expired): ${task.taskId}`
4570
+ );
4571
+ return;
4572
+ }
4573
+ const nextRunAt = getNextCronTime(task.cronExpression);
4574
+ await this.storage.update(task.taskId, {
4575
+ status: import_protocols6.ScheduledTaskStatus.PENDING,
4576
+ runCount: newRunCount,
4577
+ lastRunAt: Date.now(),
4578
+ nextRunAt: nextRunAt.getTime(),
4579
+ retryCount: 0
4580
+ // Reset retry count on success
4581
+ });
4582
+ const updatedTask = await this.storage.get(task.taskId);
4583
+ if (updatedTask) {
4584
+ this.scheduleTimer(updatedTask);
4585
+ console.log(
4586
+ `[Scheduler] Next cron run scheduled: ${task.taskId} at ${nextRunAt.toISOString()}`
4587
+ );
4588
+ }
4589
+ }
4590
+ } catch (error) {
4591
+ const errorMessage = error instanceof Error ? error.message : String(error);
4592
+ console.error(`[Scheduler] Task failed: ${task.taskId}`, error);
4593
+ const latestTask = await this.storage.get(task.taskId);
4594
+ if (!latestTask) return;
4595
+ const newRetryCount = latestTask.retryCount + 1;
4596
+ if (newRetryCount <= latestTask.maxRetries) {
4597
+ console.log(
4598
+ `[Scheduler] Retrying task: ${task.taskId} (attempt ${newRetryCount}/${latestTask.maxRetries})`
4599
+ );
4600
+ await this.storage.update(task.taskId, {
4601
+ status: import_protocols6.ScheduledTaskStatus.PENDING,
4602
+ retryCount: newRetryCount,
4603
+ lastError: errorMessage
4604
+ });
4605
+ const retryDelay = Math.min(
4606
+ 1e3 * Math.pow(2, newRetryCount - 1),
4607
+ 6e4
4608
+ );
4609
+ const retryTask = await this.storage.get(task.taskId);
4610
+ if (retryTask) {
4611
+ if (task.executionType === import_protocols6.ScheduleExecutionType.ONCE) {
4612
+ retryTask.executeAt = Date.now() + retryDelay;
4613
+ } else {
4614
+ retryTask.nextRunAt = Date.now() + retryDelay;
4615
+ }
4616
+ await this.storage.update(task.taskId, {
4617
+ executeAt: retryTask.executeAt,
4618
+ nextRunAt: retryTask.nextRunAt
4619
+ });
4620
+ this.scheduleTimer(retryTask);
4621
+ }
4622
+ } else {
4623
+ await this.storage.update(task.taskId, {
4624
+ status: import_protocols6.ScheduledTaskStatus.FAILED,
4625
+ retryCount: newRetryCount,
4626
+ lastError: errorMessage
4627
+ });
4628
+ this.timers.delete(task.taskId);
4629
+ console.error(
4630
+ `[Scheduler] Task failed permanently: ${task.taskId} (max retries exceeded)`
4631
+ );
4632
+ }
4633
+ }
4634
+ }
4635
+ };
4636
+ _DefaultScheduleClient.instance = null;
4637
+ var DefaultScheduleClient = _DefaultScheduleClient;
4638
+
4639
+ // src/schedule_lattice/ScheduleLatticeManager.ts
4640
+ var ScheduleLatticeManager = class _ScheduleLatticeManager extends BaseLatticeManager {
4641
+ /**
4642
+ * Get ScheduleLatticeManager singleton instance
4643
+ */
4644
+ static getInstance() {
4645
+ if (!_ScheduleLatticeManager._instance) {
4646
+ _ScheduleLatticeManager._instance = new _ScheduleLatticeManager();
4647
+ }
4648
+ return _ScheduleLatticeManager._instance;
4649
+ }
4650
+ /**
4651
+ * Get Lattice type prefix
4652
+ */
4653
+ getLatticeType() {
4654
+ return "schedules";
4655
+ }
4656
+ /**
4657
+ * Register schedule Lattice
4658
+ * @param key Lattice key name
4659
+ * @param config Schedule configuration
4660
+ * @param client Optional schedule client. If not provided, will create based on config type.
4661
+ */
4662
+ registerLattice(key, config, client) {
4663
+ let scheduleClient;
4664
+ if (client) {
4665
+ scheduleClient = client;
4666
+ if (config.storage) {
4667
+ scheduleClient.setStorage(config.storage);
4668
+ }
4669
+ } else {
4670
+ let storage;
4671
+ if (config.storage) {
4672
+ storage = config.storage;
4673
+ } else {
4674
+ storage = new MemoryScheduleStorage();
4675
+ }
4676
+ if (config.type === import_protocols7.ScheduleType.MEMORY) {
4677
+ scheduleClient = new DefaultScheduleClient(storage);
4678
+ } else if (config.type === import_protocols7.ScheduleType.POSTGRES) {
4679
+ if (!config.storage) {
4680
+ throw new Error(
4681
+ `PostgreSQL schedule storage must be provided. Please install @axiom-lattice/pg-stores and pass the storage in config.storage.`
4682
+ );
4683
+ }
4684
+ scheduleClient = new DefaultScheduleClient(storage);
4685
+ } else {
4686
+ scheduleClient = new DefaultScheduleClient(storage);
4687
+ }
4688
+ }
4689
+ const scheduleLattice = {
4690
+ key,
4691
+ config,
4692
+ client: scheduleClient,
4693
+ // Handler registration
4694
+ registerHandler: (taskType, handler) => {
4695
+ scheduleClient.registerHandler(taskType, handler);
4696
+ },
4697
+ unregisterHandler: (taskType) => {
4698
+ return scheduleClient.unregisterHandler(taskType);
4699
+ },
4700
+ hasHandler: (taskType) => {
4701
+ return scheduleClient.hasHandler(taskType);
4702
+ },
4703
+ getHandlerTypes: () => {
4704
+ return scheduleClient.getHandlerTypes();
4705
+ },
4706
+ // One-time task scheduling
4707
+ scheduleOnce: async (taskId, taskType, payload, options) => {
4708
+ return scheduleClient.scheduleOnce(taskId, taskType, payload, options);
4709
+ },
4710
+ // Cron task scheduling
4711
+ scheduleCron: async (taskId, taskType, payload, options) => {
4712
+ return scheduleClient.scheduleCron(taskId, taskType, payload, options);
4713
+ },
4714
+ // Task management
4715
+ cancel: async (taskId) => {
4716
+ return scheduleClient.cancel(taskId);
4717
+ },
4718
+ pause: async (taskId) => {
4719
+ return scheduleClient.pause(taskId);
4720
+ },
4721
+ resume: async (taskId) => {
4722
+ return scheduleClient.resume(taskId);
4723
+ },
4724
+ has: async (taskId) => {
4725
+ return scheduleClient.has(taskId);
4726
+ },
4727
+ getTask: async (taskId) => {
4728
+ return scheduleClient.getTask(taskId);
4729
+ },
4730
+ getRemainingTime: async (taskId) => {
4731
+ return scheduleClient.getRemainingTime(taskId);
4732
+ },
4733
+ getActiveTaskCount: async () => {
4734
+ return scheduleClient.getActiveTaskCount();
4735
+ },
4736
+ getActiveTaskIds: async () => {
4737
+ return scheduleClient.getActiveTaskIds();
4738
+ },
4739
+ cancelAll: async () => {
4740
+ return scheduleClient.cancelAll();
4741
+ },
4742
+ // Recovery
4743
+ restore: async () => {
4744
+ return scheduleClient.restore();
4745
+ }
4746
+ };
4747
+ this.register(key, scheduleLattice);
4748
+ }
4749
+ /**
4750
+ * Get ScheduleLattice
4751
+ * @param key Lattice key name
4752
+ */
4753
+ getScheduleLattice(key) {
4754
+ const scheduleLattice = this.get(key);
4755
+ if (!scheduleLattice) {
4756
+ throw new Error(`ScheduleLattice ${key} not found`);
4757
+ }
4758
+ return scheduleLattice;
4759
+ }
4760
+ /**
4761
+ * Get all Lattices
4762
+ */
4763
+ getAllLattices() {
4764
+ return this.getAll();
4765
+ }
4766
+ /**
4767
+ * Check if Lattice exists
4768
+ * @param key Lattice key name
4769
+ */
4770
+ hasLattice(key) {
4771
+ return this.has(key);
4772
+ }
4773
+ /**
4774
+ * Remove Lattice
4775
+ * @param key Lattice key name
4776
+ */
4777
+ removeLattice(key) {
4778
+ return this.remove(key);
4779
+ }
4780
+ /**
4781
+ * Clear all Lattices
4782
+ */
4783
+ clearLattices() {
4784
+ this.clear();
4785
+ }
4786
+ /**
4787
+ * Get Lattice count
4788
+ */
4789
+ getLatticeCount() {
4790
+ return this.count();
4791
+ }
4792
+ /**
4793
+ * Get Lattice key list
4794
+ */
4795
+ getLatticeKeys() {
4796
+ return this.keys();
4797
+ }
4798
+ };
4799
+ var scheduleLatticeManager = ScheduleLatticeManager.getInstance();
4800
+ var registerScheduleLattice = (key, config, client) => scheduleLatticeManager.registerLattice(key, config, client);
4801
+ var getScheduleLattice = (key) => scheduleLatticeManager.getScheduleLattice(key);
4802
+
3278
4803
  // src/store_lattice/InMemoryThreadStore.ts
3279
4804
  var InMemoryThreadStore = class {
3280
4805
  constructor() {
@@ -3778,6 +5303,7 @@ var Protocols = __toESM(require("@axiom-lattice/protocols"));
3778
5303
  AgentType,
3779
5304
  ChunkBuffer,
3780
5305
  ChunkBufferLatticeManager,
5306
+ DefaultScheduleClient,
3781
5307
  EmbeddingsLatticeManager,
3782
5308
  GraphBuildOptions,
3783
5309
  InMemoryAssistantStore,
@@ -3785,15 +5311,20 @@ var Protocols = __toESM(require("@axiom-lattice/protocols"));
3785
5311
  InMemoryThreadStore,
3786
5312
  MemoryLatticeManager,
3787
5313
  MemoryQueueClient,
5314
+ MemoryScheduleStorage,
3788
5315
  MemoryType,
3789
5316
  ModelLatticeManager,
5317
+ PostgresDatabase,
3790
5318
  Protocols,
3791
5319
  QueueLatticeManager,
5320
+ ScheduleLatticeManager,
5321
+ SqlDatabaseManager,
3792
5322
  StoreLatticeManager,
3793
5323
  ThreadStatus,
3794
5324
  ToolLatticeManager,
3795
5325
  VectorStoreLatticeManager,
3796
5326
  agentLatticeManager,
5327
+ describeCronExpression,
3797
5328
  embeddingsLatticeManager,
3798
5329
  eventBus,
3799
5330
  eventBusDefault,
@@ -3807,7 +5338,9 @@ var Protocols = __toESM(require("@axiom-lattice/protocols"));
3807
5338
  getEmbeddingsClient,
3808
5339
  getEmbeddingsLattice,
3809
5340
  getModelLattice,
5341
+ getNextCronTime,
3810
5342
  getQueueLattice,
5343
+ getScheduleLattice,
3811
5344
  getStoreLattice,
3812
5345
  getToolClient,
3813
5346
  getToolDefinition,
@@ -3815,7 +5348,9 @@ var Protocols = __toESM(require("@axiom-lattice/protocols"));
3815
5348
  getVectorStoreClient,
3816
5349
  getVectorStoreLattice,
3817
5350
  hasChunkBuffer,
5351
+ isValidCronExpression,
3818
5352
  modelLatticeManager,
5353
+ parseCronExpression,
3819
5354
  queueLatticeManager,
3820
5355
  registerAgentLattice,
3821
5356
  registerAgentLattices,
@@ -3824,9 +5359,12 @@ var Protocols = __toESM(require("@axiom-lattice/protocols"));
3824
5359
  registerEmbeddingsLattice,
3825
5360
  registerModelLattice,
3826
5361
  registerQueueLattice,
5362
+ registerScheduleLattice,
3827
5363
  registerStoreLattice,
3828
5364
  registerToolLattice,
3829
5365
  registerVectorStoreLattice,
5366
+ scheduleLatticeManager,
5367
+ sqlDatabaseManager,
3830
5368
  storeLatticeManager,
3831
5369
  toolLatticeManager,
3832
5370
  validateAgentInput,