@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.mjs CHANGED
@@ -588,6 +588,538 @@ registerToolLattice(
588
588
  }
589
589
  );
590
590
 
591
+ // src/tool_lattice/sql/list_tables_sql.ts
592
+ import z3 from "zod";
593
+
594
+ // src/tool_lattice/sql/SqlDatabaseManager.ts
595
+ var PostgresDatabase = class {
596
+ constructor(config) {
597
+ // pg.Pool
598
+ this.connected = false;
599
+ this.config = config;
600
+ }
601
+ async connect() {
602
+ if (this.connected) return;
603
+ try {
604
+ const { Pool } = await import("pg");
605
+ const poolConfig = this.config.connectionString ? { connectionString: this.config.connectionString } : {
606
+ host: this.config.host || "localhost",
607
+ port: this.config.port || 5432,
608
+ database: this.config.database,
609
+ user: this.config.user,
610
+ password: this.config.password,
611
+ ssl: this.config.ssl ? { rejectUnauthorized: false } : void 0
612
+ };
613
+ this.pool = new Pool(poolConfig);
614
+ const client = await this.pool.connect();
615
+ client.release();
616
+ this.connected = true;
617
+ } catch (error) {
618
+ throw new Error(`Failed to connect to PostgreSQL: ${error}`);
619
+ }
620
+ }
621
+ async disconnect() {
622
+ if (this.pool) {
623
+ await this.pool.end();
624
+ this.connected = false;
625
+ }
626
+ }
627
+ async listTables() {
628
+ await this.ensureConnected();
629
+ const query = `
630
+ SELECT table_name, table_schema
631
+ FROM information_schema.tables
632
+ WHERE table_schema NOT IN ('pg_catalog', 'information_schema')
633
+ AND table_type = 'BASE TABLE'
634
+ ORDER BY table_schema, table_name;
635
+ `;
636
+ const result = await this.pool.query(query);
637
+ return result.rows.map((row) => ({
638
+ name: row.table_name,
639
+ schema: row.table_schema
640
+ }));
641
+ }
642
+ async getTableInfo(tables) {
643
+ await this.ensureConnected();
644
+ const schemas = [];
645
+ for (const tableName of tables) {
646
+ const columnQuery = `
647
+ SELECT
648
+ c.column_name,
649
+ c.data_type,
650
+ c.is_nullable,
651
+ c.column_default,
652
+ CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_key,
653
+ CASE WHEN fk.column_name IS NOT NULL THEN true ELSE false END as is_foreign_key,
654
+ fk.foreign_table_name,
655
+ fk.foreign_column_name
656
+ FROM information_schema.columns c
657
+ LEFT JOIN (
658
+ SELECT ku.column_name, ku.table_name
659
+ FROM information_schema.table_constraints tc
660
+ JOIN information_schema.key_column_usage ku
661
+ ON tc.constraint_name = ku.constraint_name
662
+ WHERE tc.constraint_type = 'PRIMARY KEY'
663
+ ) pk ON c.column_name = pk.column_name AND c.table_name = pk.table_name
664
+ LEFT JOIN (
665
+ SELECT
666
+ kcu.column_name,
667
+ kcu.table_name,
668
+ ccu.table_name as foreign_table_name,
669
+ ccu.column_name as foreign_column_name
670
+ FROM information_schema.table_constraints tc
671
+ JOIN information_schema.key_column_usage kcu
672
+ ON tc.constraint_name = kcu.constraint_name
673
+ JOIN information_schema.constraint_column_usage ccu
674
+ ON tc.constraint_name = ccu.constraint_name
675
+ WHERE tc.constraint_type = 'FOREIGN KEY'
676
+ ) fk ON c.column_name = fk.column_name AND c.table_name = fk.table_name
677
+ WHERE c.table_name = $1
678
+ ORDER BY c.ordinal_position;
679
+ `;
680
+ const columnResult = await this.pool.query(columnQuery, [tableName]);
681
+ const columns = columnResult.rows.map((row) => ({
682
+ name: row.column_name,
683
+ type: row.data_type,
684
+ nullable: row.is_nullable === "YES",
685
+ default: row.column_default,
686
+ isPrimaryKey: row.is_primary_key,
687
+ isForeignKey: row.is_foreign_key,
688
+ foreignKeyRef: row.is_foreign_key ? `${row.foreign_table_name}.${row.foreign_column_name}` : void 0
689
+ }));
690
+ let sampleRows = [];
691
+ try {
692
+ const sampleQuery = `SELECT * FROM "${tableName}" LIMIT 3`;
693
+ const sampleResult = await this.pool.query(sampleQuery);
694
+ sampleRows = sampleResult.rows;
695
+ } catch {
696
+ }
697
+ schemas.push({
698
+ tableName,
699
+ columns,
700
+ sampleRows
701
+ });
702
+ }
703
+ return schemas;
704
+ }
705
+ async executeQuery(query) {
706
+ await this.ensureConnected();
707
+ const result = await this.pool.query(query);
708
+ return {
709
+ rows: result.rows,
710
+ rowCount: result.rowCount || result.rows.length,
711
+ fields: result.fields?.map((f) => f.name)
712
+ };
713
+ }
714
+ getDatabaseType() {
715
+ return "postgres";
716
+ }
717
+ async ensureConnected() {
718
+ if (!this.connected) {
719
+ await this.connect();
720
+ }
721
+ }
722
+ };
723
+ var SqlDatabaseManager = class _SqlDatabaseManager {
724
+ constructor() {
725
+ this.databases = /* @__PURE__ */ new Map();
726
+ this.defaultDatabaseKey = null;
727
+ }
728
+ /**
729
+ * Get the singleton instance
730
+ */
731
+ static getInstance() {
732
+ if (!_SqlDatabaseManager.instance) {
733
+ _SqlDatabaseManager.instance = new _SqlDatabaseManager();
734
+ }
735
+ return _SqlDatabaseManager.instance;
736
+ }
737
+ /**
738
+ * Register a database connection
739
+ * @param key - Unique identifier for the database
740
+ * @param config - Database configuration
741
+ */
742
+ registerDatabase(key, config) {
743
+ let database;
744
+ switch (config.type) {
745
+ case "postgres":
746
+ database = new PostgresDatabase(config);
747
+ break;
748
+ case "mysql":
749
+ throw new Error("MySQL support not yet implemented");
750
+ case "sqlite":
751
+ throw new Error("SQLite support not yet implemented");
752
+ default:
753
+ throw new Error(`Unsupported database type: ${config.type}`);
754
+ }
755
+ this.databases.set(key, database);
756
+ if (this.defaultDatabaseKey === null) {
757
+ this.defaultDatabaseKey = key;
758
+ }
759
+ }
760
+ /**
761
+ * Set the default database
762
+ * @param key - Database key to set as default
763
+ */
764
+ setDefaultDatabase(key) {
765
+ if (!this.databases.has(key)) {
766
+ throw new Error(`Database '${key}' not found`);
767
+ }
768
+ this.defaultDatabaseKey = key;
769
+ }
770
+ /**
771
+ * Get a database by key
772
+ * @param key - Database key (optional, uses default if not provided)
773
+ */
774
+ getDatabase(key) {
775
+ const dbKey = key || this.defaultDatabaseKey;
776
+ if (!dbKey) {
777
+ throw new Error("No database registered");
778
+ }
779
+ const database = this.databases.get(dbKey);
780
+ if (!database) {
781
+ throw new Error(`Database '${dbKey}' not found`);
782
+ }
783
+ return database;
784
+ }
785
+ /**
786
+ * Check if a database is registered
787
+ * @param key - Database key
788
+ */
789
+ hasDatabase(key) {
790
+ return this.databases.has(key);
791
+ }
792
+ /**
793
+ * Get all registered database keys
794
+ */
795
+ getDatabaseKeys() {
796
+ return Array.from(this.databases.keys());
797
+ }
798
+ /**
799
+ * Remove a database connection
800
+ * @param key - Database key
801
+ */
802
+ async removeDatabase(key) {
803
+ const database = this.databases.get(key);
804
+ if (database) {
805
+ await database.disconnect();
806
+ this.databases.delete(key);
807
+ if (this.defaultDatabaseKey === key) {
808
+ this.defaultDatabaseKey = this.databases.size > 0 ? this.databases.keys().next().value || null : null;
809
+ }
810
+ }
811
+ }
812
+ /**
813
+ * Disconnect all databases
814
+ */
815
+ async disconnectAll() {
816
+ for (const database of this.databases.values()) {
817
+ await database.disconnect();
818
+ }
819
+ }
820
+ };
821
+ var sqlDatabaseManager = SqlDatabaseManager.getInstance();
822
+
823
+ // src/tool_lattice/sql/list_tables_sql.ts
824
+ function getDatabaseKeyFromConfig(config) {
825
+ const runConfig = config.configurable?.runConfig;
826
+ return runConfig?.databaseKey;
827
+ }
828
+ registerToolLattice(
829
+ "list_tables_sql",
830
+ {
831
+ name: "list_tables_sql",
832
+ 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.",
833
+ needUserApprove: false,
834
+ schema: z3.object({})
835
+ },
836
+ async (_input, config) => {
837
+ try {
838
+ const databaseKey = getDatabaseKeyFromConfig(config);
839
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
840
+ const tables = await database.listTables();
841
+ if (tables.length === 0) {
842
+ return "No tables found in the database.";
843
+ }
844
+ const tableNames = tables.map(
845
+ (t) => t.schema && t.schema !== "public" ? `${t.schema}.${t.name}` : t.name
846
+ );
847
+ return tableNames.join(", ");
848
+ } catch (error) {
849
+ return `Error listing tables: ${error instanceof Error ? error.message : String(error)}`;
850
+ }
851
+ }
852
+ );
853
+
854
+ // src/tool_lattice/sql/info_sql.ts
855
+ import z4 from "zod";
856
+ function getDatabaseKeyFromConfig2(config) {
857
+ const runConfig = config.configurable?.runConfig;
858
+ return runConfig?.databaseKey;
859
+ }
860
+ function formatTableSchema(schema) {
861
+ const lines = [];
862
+ lines.push(`
863
+ Table: ${schema.tableName}`);
864
+ lines.push("-".repeat(40));
865
+ lines.push("Columns:");
866
+ for (const col of schema.columns) {
867
+ const constraints = [];
868
+ if (col.isPrimaryKey) constraints.push("PRIMARY KEY");
869
+ if (col.isForeignKey && col.foreignKeyRef)
870
+ constraints.push(`FK -> ${col.foreignKeyRef}`);
871
+ if (!col.nullable) constraints.push("NOT NULL");
872
+ const constraintStr = constraints.length > 0 ? ` [${constraints.join(", ")}]` : "";
873
+ lines.push(` - ${col.name}: ${col.type}${constraintStr}`);
874
+ }
875
+ if (schema.sampleRows && schema.sampleRows.length > 0) {
876
+ lines.push("\nSample Rows (up to 3):");
877
+ for (const row of schema.sampleRows) {
878
+ const rowStr = Object.entries(row).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(", ");
879
+ lines.push(` ${rowStr}`);
880
+ }
881
+ }
882
+ return lines.join("\n");
883
+ }
884
+ registerToolLattice(
885
+ "info_sql",
886
+ {
887
+ name: "info_sql",
888
+ 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.",
889
+ needUserApprove: false,
890
+ schema: z4.object({
891
+ tables: z4.string().describe(
892
+ "Comma-separated list of table names to get information for. Example: 'users, orders, products'"
893
+ )
894
+ })
895
+ },
896
+ async ({
897
+ tables
898
+ }, config) => {
899
+ try {
900
+ const databaseKey = getDatabaseKeyFromConfig2(config);
901
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
902
+ const tableNames = tables.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
903
+ if (tableNames.length === 0) {
904
+ return "Error: No table names provided. Please provide a comma-separated list of table names.";
905
+ }
906
+ const schemas = await database.getTableInfo(tableNames);
907
+ if (schemas.length === 0) {
908
+ return `No schema information found for tables: ${tableNames.join(", ")}`;
909
+ }
910
+ const output = schemas.map(formatTableSchema).join("\n");
911
+ return output;
912
+ } catch (error) {
913
+ return `Error getting table info: ${error instanceof Error ? error.message : String(error)}`;
914
+ }
915
+ }
916
+ );
917
+
918
+ // src/tool_lattice/sql/query_sql.ts
919
+ import z5 from "zod";
920
+ function getDatabaseKeyFromConfig3(config) {
921
+ const runConfig = config.configurable?.runConfig;
922
+ return runConfig?.databaseKey;
923
+ }
924
+ function formatQueryResult(rows, fields) {
925
+ if (rows.length === 0) {
926
+ return "Query executed successfully. No rows returned.";
927
+ }
928
+ const lines = [];
929
+ const columns = fields || Object.keys(rows[0]);
930
+ lines.push(columns.join(" | "));
931
+ lines.push("-".repeat(columns.join(" | ").length));
932
+ const maxRows = 50;
933
+ const displayRows = rows.slice(0, maxRows);
934
+ for (const row of displayRows) {
935
+ const values = columns.map((col) => {
936
+ const val = row[col];
937
+ if (val === null) return "NULL";
938
+ if (typeof val === "object") return JSON.stringify(val);
939
+ return String(val);
940
+ });
941
+ lines.push(values.join(" | "));
942
+ }
943
+ if (rows.length > maxRows) {
944
+ lines.push(`
945
+ ... (${rows.length - maxRows} more rows not shown)`);
946
+ }
947
+ lines.push(`
948
+ Total rows: ${rows.length}`);
949
+ return lines.join("\n");
950
+ }
951
+ registerToolLattice(
952
+ "query_sql",
953
+ {
954
+ name: "query_sql",
955
+ 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.",
956
+ needUserApprove: false,
957
+ // SQL queries should require user approval for safety
958
+ schema: z5.object({
959
+ query: z5.string().describe(
960
+ "The SQL query to execute. Should be a valid SELECT, INSERT, UPDATE, or DELETE statement."
961
+ )
962
+ })
963
+ },
964
+ async ({
965
+ query
966
+ }, config) => {
967
+ try {
968
+ const databaseKey = getDatabaseKeyFromConfig3(config);
969
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
970
+ const trimmedQuery = query.trim();
971
+ if (!trimmedQuery) {
972
+ return "Error: Empty query provided. Please provide a valid SQL query.";
973
+ }
974
+ const result = await database.executeQuery(trimmedQuery);
975
+ return formatQueryResult(result.rows, result.fields);
976
+ } catch (error) {
977
+ return `Error executing query: ${error instanceof Error ? error.message : String(error)}`;
978
+ }
979
+ }
980
+ );
981
+
982
+ // src/tool_lattice/sql/query_checker_sql.ts
983
+ import z6 from "zod";
984
+ function getDatabaseKeyFromConfig4(config) {
985
+ const runConfig = config.configurable?.runConfig;
986
+ return runConfig?.databaseKey;
987
+ }
988
+ var DANGEROUS_KEYWORDS = [
989
+ "DROP",
990
+ "TRUNCATE",
991
+ "DELETE",
992
+ "ALTER",
993
+ "CREATE",
994
+ "GRANT",
995
+ "REVOKE"
996
+ ];
997
+ function checkSyntax(query) {
998
+ const issues = [];
999
+ const upperQuery = query.toUpperCase();
1000
+ let parenCount = 0;
1001
+ for (const char of query) {
1002
+ if (char === "(") parenCount++;
1003
+ if (char === ")") parenCount--;
1004
+ if (parenCount < 0) {
1005
+ issues.push("Unbalanced parentheses: found closing ) without matching (");
1006
+ break;
1007
+ }
1008
+ }
1009
+ if (parenCount > 0) {
1010
+ issues.push("Unbalanced parentheses: missing closing )");
1011
+ }
1012
+ const singleQuotes = (query.match(/'/g) || []).length;
1013
+ if (singleQuotes % 2 !== 0) {
1014
+ issues.push("Unbalanced single quotes");
1015
+ }
1016
+ if (upperQuery.includes("SELECT *") && upperQuery.includes("JOIN")) {
1017
+ issues.push(
1018
+ "Warning: SELECT * with JOIN may return duplicate column names. Consider specifying columns explicitly."
1019
+ );
1020
+ }
1021
+ if ((upperQuery.includes("UPDATE ") || upperQuery.includes("DELETE FROM ")) && !upperQuery.includes("WHERE ")) {
1022
+ issues.push(
1023
+ "Warning: UPDATE or DELETE without WHERE clause will affect all rows in the table."
1024
+ );
1025
+ }
1026
+ if (upperQuery.includes("GROUP BY") && !upperQuery.match(/\b(COUNT|SUM|AVG|MAX|MIN|ARRAY_AGG|STRING_AGG)\s*\(/i)) {
1027
+ issues.push(
1028
+ "Warning: GROUP BY used but no aggregate functions found. Make sure all non-aggregated columns are in GROUP BY."
1029
+ );
1030
+ }
1031
+ return issues;
1032
+ }
1033
+ function checkDangerousOperations(query) {
1034
+ const warnings = [];
1035
+ const upperQuery = query.toUpperCase();
1036
+ for (const keyword of DANGEROUS_KEYWORDS) {
1037
+ if (upperQuery.includes(keyword)) {
1038
+ warnings.push(
1039
+ `Warning: Query contains potentially dangerous operation: ${keyword}`
1040
+ );
1041
+ }
1042
+ }
1043
+ return warnings;
1044
+ }
1045
+ registerToolLattice(
1046
+ "query_checker_sql",
1047
+ {
1048
+ name: "query_checker_sql",
1049
+ 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.",
1050
+ needUserApprove: false,
1051
+ schema: z6.object({
1052
+ query: z6.string().describe("The SQL query to check and validate.")
1053
+ })
1054
+ },
1055
+ async ({
1056
+ query
1057
+ }, config) => {
1058
+ try {
1059
+ const trimmedQuery = query.trim();
1060
+ if (!trimmedQuery) {
1061
+ return "Error: Empty query provided. Please provide a SQL query to check.";
1062
+ }
1063
+ const results = [];
1064
+ results.push("SQL Query Check Results:");
1065
+ results.push("=".repeat(40));
1066
+ results.push(`
1067
+ Query:
1068
+ ${trimmedQuery}
1069
+ `);
1070
+ const syntaxIssues = checkSyntax(trimmedQuery);
1071
+ if (syntaxIssues.length > 0) {
1072
+ results.push("Syntax Issues:");
1073
+ for (const issue of syntaxIssues) {
1074
+ results.push(` - ${issue}`);
1075
+ }
1076
+ } else {
1077
+ results.push("Syntax: \u2713 No obvious syntax issues found");
1078
+ }
1079
+ const dangerWarnings = checkDangerousOperations(trimmedQuery);
1080
+ if (dangerWarnings.length > 0) {
1081
+ results.push("\nSafety Warnings:");
1082
+ for (const warning of dangerWarnings) {
1083
+ results.push(` - ${warning}`);
1084
+ }
1085
+ } else {
1086
+ results.push("Safety: \u2713 No dangerous operations detected");
1087
+ }
1088
+ try {
1089
+ const databaseKey = getDatabaseKeyFromConfig4(config);
1090
+ const database = sqlDatabaseManager.getDatabase(databaseKey);
1091
+ const dbType = database.getDatabaseType();
1092
+ if (dbType === "postgres") {
1093
+ try {
1094
+ await database.executeQuery(`EXPLAIN ${trimmedQuery}`);
1095
+ results.push("Database Validation: \u2713 Query is valid against database schema");
1096
+ } catch (explainError) {
1097
+ results.push(
1098
+ `Database Validation: \u2717 ${explainError instanceof Error ? explainError.message : String(explainError)}`
1099
+ );
1100
+ }
1101
+ }
1102
+ } catch {
1103
+ results.push(
1104
+ "Database Validation: Skipped (no database connection available)"
1105
+ );
1106
+ }
1107
+ const hasErrors = syntaxIssues.some((i) => !i.startsWith("Warning:")) || dangerWarnings.length > 0;
1108
+ results.push("\n" + "=".repeat(40));
1109
+ if (hasErrors) {
1110
+ results.push(
1111
+ "Overall: \u26A0\uFE0F Query has potential issues. Review warnings before execution."
1112
+ );
1113
+ } else {
1114
+ results.push("Overall: \u2713 Query appears to be safe to execute.");
1115
+ }
1116
+ return results.join("\n");
1117
+ } catch (error) {
1118
+ return `Error checking query: ${error instanceof Error ? error.message : String(error)}`;
1119
+ }
1120
+ }
1121
+ );
1122
+
591
1123
  // src/agent_lattice/types.ts
592
1124
  import {
593
1125
  AgentType,
@@ -729,7 +1261,7 @@ import {
729
1261
  // src/deep_agent_new/middleware/fs.ts
730
1262
  import { createMiddleware, tool as tool2, ToolMessage } from "langchain";
731
1263
  import { Command, isCommand, getCurrentTaskInput } from "@langchain/langgraph";
732
- import { z as z3 } from "zod/v3";
1264
+ import { z as z32 } from "zod/v3";
733
1265
  import { withLangGraph } from "@langchain/langgraph/zod";
734
1266
 
735
1267
  // src/deep_agent_new/backends/utils.ts
@@ -1072,10 +1604,10 @@ var StateBackend = class {
1072
1604
  };
1073
1605
 
1074
1606
  // src/deep_agent_new/middleware/fs.ts
1075
- var FileDataSchema = z3.object({
1076
- content: z3.array(z3.string()),
1077
- created_at: z3.string(),
1078
- modified_at: z3.string()
1607
+ var FileDataSchema = z32.object({
1608
+ content: z32.array(z32.string()),
1609
+ created_at: z32.string(),
1610
+ modified_at: z32.string()
1079
1611
  });
1080
1612
  function fileDataReducer(left, right) {
1081
1613
  if (left === void 0) {
@@ -1097,13 +1629,13 @@ function fileDataReducer(left, right) {
1097
1629
  }
1098
1630
  return result;
1099
1631
  }
1100
- var FilesystemStateSchema = z3.object({
1632
+ var FilesystemStateSchema = z32.object({
1101
1633
  files: withLangGraph(
1102
- z3.record(z3.string(), FileDataSchema).default({}),
1634
+ z32.record(z32.string(), FileDataSchema).default({}),
1103
1635
  {
1104
1636
  reducer: {
1105
1637
  fn: fileDataReducer,
1106
- schema: z3.record(z3.string(), FileDataSchema.nullable())
1638
+ schema: z32.record(z32.string(), FileDataSchema.nullable())
1107
1639
  }
1108
1640
  }
1109
1641
  )
@@ -1156,8 +1688,8 @@ function createLsTool(backend, options) {
1156
1688
  {
1157
1689
  name: "ls",
1158
1690
  description: customDescription || LS_TOOL_DESCRIPTION,
1159
- schema: z3.object({
1160
- path: z3.string().optional().default("/").describe("Directory path to list (default: /)")
1691
+ schema: z32.object({
1692
+ path: z32.string().optional().default("/").describe("Directory path to list (default: /)")
1161
1693
  })
1162
1694
  }
1163
1695
  );
@@ -1177,10 +1709,10 @@ function createReadFileTool(backend, options) {
1177
1709
  {
1178
1710
  name: "read_file",
1179
1711
  description: customDescription || READ_FILE_TOOL_DESCRIPTION,
1180
- schema: z3.object({
1181
- file_path: z3.string().describe("Absolute path to the file to read"),
1182
- offset: z3.number({ coerce: true }).optional().default(0).describe("Line offset to start reading from (0-indexed)"),
1183
- limit: z3.number({ coerce: true }).optional().default(2e3).describe("Maximum number of lines to read")
1712
+ schema: z32.object({
1713
+ file_path: z32.string().describe("Absolute path to the file to read"),
1714
+ offset: z32.number({ coerce: true }).optional().default(0).describe("Line offset to start reading from (0-indexed)"),
1715
+ limit: z32.number({ coerce: true }).optional().default(2e3).describe("Maximum number of lines to read")
1184
1716
  })
1185
1717
  }
1186
1718
  );
@@ -1215,9 +1747,9 @@ function createWriteFileTool(backend, options) {
1215
1747
  {
1216
1748
  name: "write_file",
1217
1749
  description: customDescription || WRITE_FILE_TOOL_DESCRIPTION,
1218
- schema: z3.object({
1219
- file_path: z3.string().describe("Absolute path to the file to write"),
1220
- content: z3.string().describe("Content to write to the file")
1750
+ schema: z32.object({
1751
+ file_path: z32.string().describe("Absolute path to the file to write"),
1752
+ content: z32.string().describe("Content to write to the file")
1221
1753
  })
1222
1754
  }
1223
1755
  );
@@ -1257,11 +1789,11 @@ function createEditFileTool(backend, options) {
1257
1789
  {
1258
1790
  name: "edit_file",
1259
1791
  description: customDescription || EDIT_FILE_TOOL_DESCRIPTION,
1260
- schema: z3.object({
1261
- file_path: z3.string().describe("Absolute path to the file to edit"),
1262
- old_string: z3.string().describe("String to be replaced (must match exactly)"),
1263
- new_string: z3.string().describe("String to replace with"),
1264
- replace_all: z3.boolean().optional().default(false).describe("Whether to replace all occurrences")
1792
+ schema: z32.object({
1793
+ file_path: z32.string().describe("Absolute path to the file to edit"),
1794
+ old_string: z32.string().describe("String to be replaced (must match exactly)"),
1795
+ new_string: z32.string().describe("String to replace with"),
1796
+ replace_all: z32.boolean().optional().default(false).describe("Whether to replace all occurrences")
1265
1797
  })
1266
1798
  }
1267
1799
  );
@@ -1285,9 +1817,9 @@ function createGlobTool(backend, options) {
1285
1817
  {
1286
1818
  name: "glob",
1287
1819
  description: customDescription || GLOB_TOOL_DESCRIPTION,
1288
- schema: z3.object({
1289
- pattern: z3.string().describe("Glob pattern (e.g., '*.py', '**/*.ts')"),
1290
- path: z3.string().optional().default("/").describe("Base path to search from (default: /)")
1820
+ schema: z32.object({
1821
+ pattern: z32.string().describe("Glob pattern (e.g., '*.py', '**/*.ts')"),
1822
+ path: z32.string().optional().default("/").describe("Base path to search from (default: /)")
1291
1823
  })
1292
1824
  }
1293
1825
  );
@@ -1324,10 +1856,10 @@ ${currentFile}:`);
1324
1856
  {
1325
1857
  name: "grep",
1326
1858
  description: customDescription || GREP_TOOL_DESCRIPTION,
1327
- schema: z3.object({
1328
- pattern: z3.string().describe("Regex pattern to search for"),
1329
- path: z3.string().optional().default("/").describe("Base path to search from (default: /)"),
1330
- glob: z3.string().optional().nullable().describe("Optional glob pattern to filter files (e.g., '*.py')")
1859
+ schema: z32.object({
1860
+ pattern: z32.string().describe("Regex pattern to search for"),
1861
+ path: z32.string().optional().default("/").describe("Base path to search from (default: /)"),
1862
+ glob: z32.string().optional().nullable().describe("Optional glob pattern to filter files (e.g., '*.py')")
1331
1863
  })
1332
1864
  }
1333
1865
  );
@@ -1455,7 +1987,7 @@ ${systemPrompt}` : systemPrompt;
1455
1987
  }
1456
1988
 
1457
1989
  // src/deep_agent_new/middleware/subagents.ts
1458
- import { z as z4 } from "zod/v3";
1990
+ import { z as z7 } from "zod/v3";
1459
1991
  import {
1460
1992
  createMiddleware as createMiddleware2,
1461
1993
  createAgent as createAgent2,
@@ -2132,9 +2664,9 @@ function createTaskTool(options) {
2132
2664
  {
2133
2665
  name: "task",
2134
2666
  description: finalTaskDescription,
2135
- schema: z4.object({
2136
- description: z4.string().describe("The task to execute with the selected agent"),
2137
- subagent_type: z4.string().describe(
2667
+ schema: z7.object({
2668
+ description: z7.string().describe("The task to execute with the selected agent"),
2669
+ subagent_type: z7.string().describe(
2138
2670
  `Name of the agent to use. Available: ${Object.keys(
2139
2671
  subagentGraphs
2140
2672
  ).join(", ")}`
@@ -2238,7 +2770,7 @@ var SUPPORTS_NOFOLLOW = fsSync.constants.O_NOFOLLOW !== void 0;
2238
2770
 
2239
2771
  // src/deep_agent_new/middleware/todos.ts
2240
2772
  import { Command as Command3 } from "@langchain/langgraph";
2241
- import { z as z5 } from "zod";
2773
+ import { z as z8 } from "zod";
2242
2774
  import { createMiddleware as createMiddleware4, tool as tool4, ToolMessage as ToolMessage4 } from "langchain";
2243
2775
  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.
2244
2776
  It also helps the user understand the progress of the task and overall progress of their requests.
@@ -2466,12 +2998,12 @@ Writing todos takes time and tokens, use it when it is helpful for managing comp
2466
2998
  ## Important To-Do List Usage Notes to Remember
2467
2999
  - The \`write_todos\` tool should never be called multiple times in parallel.
2468
3000
  - 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.`;
2469
- var TodoStatus = z5.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
2470
- var TodoSchema = z5.object({
2471
- content: z5.string().describe("Content of the todo item"),
3001
+ var TodoStatus = z8.enum(["pending", "in_progress", "completed"]).describe("Status of the todo");
3002
+ var TodoSchema = z8.object({
3003
+ content: z8.string().describe("Content of the todo item"),
2472
3004
  status: TodoStatus
2473
3005
  });
2474
- var stateSchema = z5.object({ todos: z5.array(TodoSchema).default([]) });
3006
+ var stateSchema = z8.object({ todos: z8.array(TodoSchema).default([]) });
2475
3007
  function todoListMiddleware(options) {
2476
3008
  const writeTodos = tool4(
2477
3009
  ({ todos }, config) => {
@@ -2490,8 +3022,8 @@ function todoListMiddleware(options) {
2490
3022
  {
2491
3023
  name: "write_todos",
2492
3024
  description: options?.toolDescription ?? WRITE_TODOS_DESCRIPTION,
2493
- schema: z5.object({
2494
- todos: z5.array(TodoSchema).describe("List of todo items to update")
3025
+ schema: z8.object({
3026
+ todos: z8.array(TodoSchema).describe("List of todo items to update")
2495
3027
  })
2496
3028
  }
2497
3029
  );
@@ -3226,6 +3758,993 @@ var getChunkBuffer = (key) => ChunkBufferLatticeManager.getInstance().get(key);
3226
3758
  var registerChunkBuffer = (key, buffer) => ChunkBufferLatticeManager.getInstance().register(key, buffer);
3227
3759
  var hasChunkBuffer = (key) => ChunkBufferLatticeManager.getInstance().has(key);
3228
3760
 
3761
+ // src/schedule_lattice/ScheduleLatticeManager.ts
3762
+ import {
3763
+ ScheduleType
3764
+ } from "@axiom-lattice/protocols";
3765
+
3766
+ // src/schedule_lattice/DefaultScheduleClient.ts
3767
+ import {
3768
+ ScheduledTaskStatus as ScheduledTaskStatus2,
3769
+ ScheduleExecutionType as ScheduleExecutionType2
3770
+ } from "@axiom-lattice/protocols";
3771
+
3772
+ // src/schedule_lattice/MemoryScheduleStorage.ts
3773
+ import {
3774
+ ScheduledTaskStatus
3775
+ } from "@axiom-lattice/protocols";
3776
+ var MemoryScheduleStorage = class {
3777
+ constructor() {
3778
+ this.tasks = /* @__PURE__ */ new Map();
3779
+ }
3780
+ /**
3781
+ * Save a new task
3782
+ */
3783
+ async save(task) {
3784
+ this.tasks.set(task.taskId, { ...task });
3785
+ }
3786
+ /**
3787
+ * Get task by ID
3788
+ */
3789
+ async get(taskId) {
3790
+ const task = this.tasks.get(taskId);
3791
+ return task ? { ...task } : null;
3792
+ }
3793
+ /**
3794
+ * Update task
3795
+ */
3796
+ async update(taskId, updates) {
3797
+ const task = this.tasks.get(taskId);
3798
+ if (task) {
3799
+ this.tasks.set(taskId, {
3800
+ ...task,
3801
+ ...updates,
3802
+ updatedAt: Date.now()
3803
+ });
3804
+ }
3805
+ }
3806
+ /**
3807
+ * Delete task
3808
+ */
3809
+ async delete(taskId) {
3810
+ this.tasks.delete(taskId);
3811
+ }
3812
+ /**
3813
+ * Get all active tasks (pending or paused)
3814
+ */
3815
+ async getActiveTasks() {
3816
+ const result = [];
3817
+ for (const task of this.tasks.values()) {
3818
+ if (task.status === ScheduledTaskStatus.PENDING || task.status === ScheduledTaskStatus.PAUSED) {
3819
+ result.push({ ...task });
3820
+ }
3821
+ }
3822
+ return result;
3823
+ }
3824
+ /**
3825
+ * Get tasks by type
3826
+ */
3827
+ async getTasksByType(taskType) {
3828
+ const result = [];
3829
+ for (const task of this.tasks.values()) {
3830
+ if (task.taskType === taskType) {
3831
+ result.push({ ...task });
3832
+ }
3833
+ }
3834
+ return result;
3835
+ }
3836
+ /**
3837
+ * Get tasks by status
3838
+ */
3839
+ async getTasksByStatus(status) {
3840
+ const result = [];
3841
+ for (const task of this.tasks.values()) {
3842
+ if (task.status === status) {
3843
+ result.push({ ...task });
3844
+ }
3845
+ }
3846
+ return result;
3847
+ }
3848
+ /**
3849
+ * Get tasks by execution type
3850
+ */
3851
+ async getTasksByExecutionType(executionType) {
3852
+ const result = [];
3853
+ for (const task of this.tasks.values()) {
3854
+ if (task.executionType === executionType) {
3855
+ result.push({ ...task });
3856
+ }
3857
+ }
3858
+ return result;
3859
+ }
3860
+ /**
3861
+ * Get tasks by assistant ID
3862
+ */
3863
+ async getTasksByAssistantId(assistantId) {
3864
+ const result = [];
3865
+ for (const task of this.tasks.values()) {
3866
+ if (task.assistantId === assistantId) {
3867
+ result.push({ ...task });
3868
+ }
3869
+ }
3870
+ return result;
3871
+ }
3872
+ /**
3873
+ * Get tasks by thread ID
3874
+ */
3875
+ async getTasksByThreadId(threadId) {
3876
+ const result = [];
3877
+ for (const task of this.tasks.values()) {
3878
+ if (task.threadId === threadId) {
3879
+ result.push({ ...task });
3880
+ }
3881
+ }
3882
+ return result;
3883
+ }
3884
+ /**
3885
+ * Get all tasks with optional filters
3886
+ */
3887
+ async getAllTasks(filters) {
3888
+ let result = [];
3889
+ for (const task of this.tasks.values()) {
3890
+ let match = true;
3891
+ if (filters?.status !== void 0 && task.status !== filters.status) {
3892
+ match = false;
3893
+ }
3894
+ if (filters?.executionType !== void 0 && task.executionType !== filters.executionType) {
3895
+ match = false;
3896
+ }
3897
+ if (filters?.taskType !== void 0 && task.taskType !== filters.taskType) {
3898
+ match = false;
3899
+ }
3900
+ if (filters?.assistantId !== void 0 && task.assistantId !== filters.assistantId) {
3901
+ match = false;
3902
+ }
3903
+ if (filters?.threadId !== void 0 && task.threadId !== filters.threadId) {
3904
+ match = false;
3905
+ }
3906
+ if (match) {
3907
+ result.push({ ...task });
3908
+ }
3909
+ }
3910
+ result.sort((a, b) => b.createdAt - a.createdAt);
3911
+ const offset = filters?.offset || 0;
3912
+ const limit = filters?.limit;
3913
+ if (limit !== void 0) {
3914
+ result = result.slice(offset, offset + limit);
3915
+ } else if (offset > 0) {
3916
+ result = result.slice(offset);
3917
+ }
3918
+ return result;
3919
+ }
3920
+ /**
3921
+ * Count tasks with optional filters
3922
+ */
3923
+ async countTasks(filters) {
3924
+ let count = 0;
3925
+ for (const task of this.tasks.values()) {
3926
+ let match = true;
3927
+ if (filters?.status !== void 0 && task.status !== filters.status) {
3928
+ match = false;
3929
+ }
3930
+ if (filters?.executionType !== void 0 && task.executionType !== filters.executionType) {
3931
+ match = false;
3932
+ }
3933
+ if (filters?.taskType !== void 0 && task.taskType !== filters.taskType) {
3934
+ match = false;
3935
+ }
3936
+ if (filters?.assistantId !== void 0 && task.assistantId !== filters.assistantId) {
3937
+ match = false;
3938
+ }
3939
+ if (filters?.threadId !== void 0 && task.threadId !== filters.threadId) {
3940
+ match = false;
3941
+ }
3942
+ if (match) {
3943
+ count++;
3944
+ }
3945
+ }
3946
+ return count;
3947
+ }
3948
+ /**
3949
+ * Delete completed/cancelled tasks older than specified time
3950
+ */
3951
+ async deleteOldTasks(olderThanMs) {
3952
+ const cutoff = Date.now() - olderThanMs;
3953
+ let deleted = 0;
3954
+ for (const [taskId, task] of this.tasks.entries()) {
3955
+ if ((task.status === ScheduledTaskStatus.COMPLETED || task.status === ScheduledTaskStatus.CANCELLED || task.status === ScheduledTaskStatus.FAILED) && task.updatedAt < cutoff) {
3956
+ this.tasks.delete(taskId);
3957
+ deleted++;
3958
+ }
3959
+ }
3960
+ return deleted;
3961
+ }
3962
+ /**
3963
+ * Clear all tasks (useful for testing)
3964
+ */
3965
+ clear() {
3966
+ this.tasks.clear();
3967
+ }
3968
+ /**
3969
+ * Get total task count (useful for debugging)
3970
+ */
3971
+ size() {
3972
+ return this.tasks.size;
3973
+ }
3974
+ };
3975
+
3976
+ // src/schedule_lattice/CronParser.ts
3977
+ function parseCronExpression(expression) {
3978
+ const parts = expression.trim().split(/\s+/);
3979
+ if (parts.length !== 5) {
3980
+ throw new Error(
3981
+ `Invalid cron expression: expected 5 fields, got ${parts.length}`
3982
+ );
3983
+ }
3984
+ return {
3985
+ minute: parseField(parts[0], 0, 59),
3986
+ hour: parseField(parts[1], 0, 23),
3987
+ dayOfMonth: parseField(parts[2], 1, 31),
3988
+ month: parseField(parts[3], 1, 12),
3989
+ dayOfWeek: parseField(parts[4], 0, 7).map((d) => d === 7 ? 0 : d)
3990
+ // Normalize Sunday
3991
+ };
3992
+ }
3993
+ function parseField(field, min, max) {
3994
+ const values = /* @__PURE__ */ new Set();
3995
+ const segments = field.split(",");
3996
+ for (const segment of segments) {
3997
+ const [range, stepStr] = segment.split("/");
3998
+ const step = stepStr ? parseInt(stepStr, 10) : 1;
3999
+ if (isNaN(step) || step < 1) {
4000
+ throw new Error(`Invalid step value: ${stepStr}`);
4001
+ }
4002
+ let rangeStart;
4003
+ let rangeEnd;
4004
+ if (range === "*") {
4005
+ rangeStart = min;
4006
+ rangeEnd = max;
4007
+ } else if (range.includes("-")) {
4008
+ const [startStr, endStr] = range.split("-");
4009
+ rangeStart = parseInt(startStr, 10);
4010
+ rangeEnd = parseInt(endStr, 10);
4011
+ if (isNaN(rangeStart) || isNaN(rangeEnd)) {
4012
+ throw new Error(`Invalid range: ${range}`);
4013
+ }
4014
+ } else {
4015
+ const value = parseInt(range, 10);
4016
+ if (isNaN(value)) {
4017
+ throw new Error(`Invalid value: ${range}`);
4018
+ }
4019
+ rangeStart = value;
4020
+ rangeEnd = value;
4021
+ }
4022
+ if (rangeStart < min || rangeEnd > max || rangeStart > rangeEnd) {
4023
+ throw new Error(`Value out of range: ${range} (expected ${min}-${max})`);
4024
+ }
4025
+ for (let i = rangeStart; i <= rangeEnd; i += step) {
4026
+ values.add(i);
4027
+ }
4028
+ }
4029
+ return Array.from(values).sort((a, b) => a - b);
4030
+ }
4031
+ function getNextCronTime(expression, after = /* @__PURE__ */ new Date(), timezone) {
4032
+ const fields = parseCronExpression(expression);
4033
+ const next = new Date(after.getTime());
4034
+ next.setSeconds(0, 0);
4035
+ next.setMinutes(next.getMinutes() + 1);
4036
+ const maxIterations = 366 * 24 * 60;
4037
+ let iterations = 0;
4038
+ while (iterations < maxIterations) {
4039
+ iterations++;
4040
+ const month = next.getMonth() + 1;
4041
+ if (!fields.month.includes(month)) {
4042
+ const nextMonth = fields.month.find((m) => m > month);
4043
+ if (nextMonth !== void 0) {
4044
+ next.setMonth(nextMonth - 1, 1);
4045
+ } else {
4046
+ next.setFullYear(next.getFullYear() + 1);
4047
+ next.setMonth(fields.month[0] - 1, 1);
4048
+ }
4049
+ next.setHours(fields.hour[0], fields.minute[0], 0, 0);
4050
+ continue;
4051
+ }
4052
+ const dayOfMonth = next.getDate();
4053
+ const maxDayOfMonth = new Date(
4054
+ next.getFullYear(),
4055
+ next.getMonth() + 1,
4056
+ 0
4057
+ ).getDate();
4058
+ const dayOfWeek = next.getDay();
4059
+ const dayOfMonthMatch = fields.dayOfMonth.includes(dayOfMonth);
4060
+ const dayOfWeekMatch = fields.dayOfWeek.includes(dayOfWeek);
4061
+ const dayOfMonthWildcard = fields.dayOfMonth.length === 31 && fields.dayOfMonth[0] === 1 && fields.dayOfMonth[30] === 31;
4062
+ const dayOfWeekWildcard = fields.dayOfWeek.length >= 7 || fields.dayOfWeek.length === 1 && fields.dayOfWeek.includes(0);
4063
+ let dayMatch;
4064
+ if (dayOfMonthWildcard && dayOfWeekWildcard) {
4065
+ dayMatch = true;
4066
+ } else if (dayOfMonthWildcard) {
4067
+ dayMatch = dayOfWeekMatch;
4068
+ } else if (dayOfWeekWildcard) {
4069
+ dayMatch = dayOfMonthMatch;
4070
+ } else {
4071
+ dayMatch = dayOfMonthMatch || dayOfWeekMatch;
4072
+ }
4073
+ if (!dayMatch || dayOfMonth > maxDayOfMonth) {
4074
+ next.setDate(next.getDate() + 1);
4075
+ next.setHours(fields.hour[0], fields.minute[0], 0, 0);
4076
+ continue;
4077
+ }
4078
+ const hour = next.getHours();
4079
+ if (!fields.hour.includes(hour)) {
4080
+ const nextHour = fields.hour.find((h) => h > hour);
4081
+ if (nextHour !== void 0) {
4082
+ next.setHours(nextHour, fields.minute[0], 0, 0);
4083
+ } else {
4084
+ next.setDate(next.getDate() + 1);
4085
+ next.setHours(fields.hour[0], fields.minute[0], 0, 0);
4086
+ }
4087
+ continue;
4088
+ }
4089
+ const minute = next.getMinutes();
4090
+ if (!fields.minute.includes(minute)) {
4091
+ const nextMinute = fields.minute.find((m) => m > minute);
4092
+ if (nextMinute !== void 0) {
4093
+ next.setMinutes(nextMinute, 0, 0);
4094
+ } else {
4095
+ next.setHours(next.getHours() + 1, fields.minute[0], 0, 0);
4096
+ }
4097
+ continue;
4098
+ }
4099
+ return next;
4100
+ }
4101
+ throw new Error("Could not find next cron time within 1 year");
4102
+ }
4103
+ function isValidCronExpression(expression) {
4104
+ try {
4105
+ parseCronExpression(expression);
4106
+ return true;
4107
+ } catch {
4108
+ return false;
4109
+ }
4110
+ }
4111
+ function describeCronExpression(expression) {
4112
+ const fields = parseCronExpression(expression);
4113
+ const parts = [];
4114
+ if (fields.minute.length === 60) {
4115
+ parts.push("every minute");
4116
+ } else if (fields.minute.length === 1) {
4117
+ parts.push(`at minute ${fields.minute[0]}`);
4118
+ } else {
4119
+ parts.push(`at minutes ${fields.minute.join(", ")}`);
4120
+ }
4121
+ if (fields.hour.length === 24) {
4122
+ parts.push("of every hour");
4123
+ } else if (fields.hour.length === 1) {
4124
+ parts.push(`of hour ${fields.hour[0]}`);
4125
+ } else {
4126
+ parts.push(`of hours ${fields.hour.join(", ")}`);
4127
+ }
4128
+ if (fields.dayOfMonth.length < 31) {
4129
+ if (fields.dayOfMonth.length === 1) {
4130
+ parts.push(`on day ${fields.dayOfMonth[0]}`);
4131
+ } else {
4132
+ parts.push(`on days ${fields.dayOfMonth.join(", ")}`);
4133
+ }
4134
+ }
4135
+ const monthNames = [
4136
+ "",
4137
+ "Jan",
4138
+ "Feb",
4139
+ "Mar",
4140
+ "Apr",
4141
+ "May",
4142
+ "Jun",
4143
+ "Jul",
4144
+ "Aug",
4145
+ "Sep",
4146
+ "Oct",
4147
+ "Nov",
4148
+ "Dec"
4149
+ ];
4150
+ if (fields.month.length < 12) {
4151
+ const months = fields.month.map((m) => monthNames[m]);
4152
+ parts.push(`in ${months.join(", ")}`);
4153
+ }
4154
+ const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
4155
+ const uniqueDays = [...new Set(fields.dayOfWeek)];
4156
+ if (uniqueDays.length < 7) {
4157
+ const days = uniqueDays.map((d) => dayNames[d]);
4158
+ parts.push(`on ${days.join(", ")}`);
4159
+ }
4160
+ return parts.join(" ");
4161
+ }
4162
+
4163
+ // src/schedule_lattice/DefaultScheduleClient.ts
4164
+ var _DefaultScheduleClient = class _DefaultScheduleClient {
4165
+ constructor(storage) {
4166
+ this.handlers = /* @__PURE__ */ new Map();
4167
+ this.timers = /* @__PURE__ */ new Map();
4168
+ this.storage = storage || new MemoryScheduleStorage();
4169
+ }
4170
+ /**
4171
+ * Get the singleton instance of DefaultScheduleClient
4172
+ */
4173
+ static getInstance(storage) {
4174
+ if (!_DefaultScheduleClient.instance) {
4175
+ _DefaultScheduleClient.instance = new _DefaultScheduleClient(storage);
4176
+ }
4177
+ return _DefaultScheduleClient.instance;
4178
+ }
4179
+ /**
4180
+ * Reset the singleton instance (useful for testing)
4181
+ */
4182
+ static resetInstance() {
4183
+ if (_DefaultScheduleClient.instance) {
4184
+ _DefaultScheduleClient.instance.cancelAll();
4185
+ _DefaultScheduleClient.instance = null;
4186
+ }
4187
+ }
4188
+ // ===== Handler Registration =====
4189
+ registerHandler(taskType, handler) {
4190
+ this.handlers.set(taskType, handler);
4191
+ console.log(`[Scheduler] Handler registered for task type: ${taskType}`);
4192
+ }
4193
+ unregisterHandler(taskType) {
4194
+ const result = this.handlers.delete(taskType);
4195
+ if (result) {
4196
+ console.log(
4197
+ `[Scheduler] Handler unregistered for task type: ${taskType}`
4198
+ );
4199
+ }
4200
+ return result;
4201
+ }
4202
+ hasHandler(taskType) {
4203
+ return this.handlers.has(taskType);
4204
+ }
4205
+ getHandlerTypes() {
4206
+ return Array.from(this.handlers.keys());
4207
+ }
4208
+ // ===== One-time Task Scheduling =====
4209
+ async scheduleOnce(taskId, taskType, payload, options) {
4210
+ if (!this.handlers.has(taskType)) {
4211
+ console.error(
4212
+ `[Scheduler] No handler registered for task type: ${taskType}`
4213
+ );
4214
+ return false;
4215
+ }
4216
+ let executeAt;
4217
+ if (options.executeAt !== void 0) {
4218
+ executeAt = options.executeAt;
4219
+ } else if (options.delayMs !== void 0) {
4220
+ executeAt = Date.now() + options.delayMs;
4221
+ } else {
4222
+ console.error("[Scheduler] Either executeAt or delayMs must be provided");
4223
+ return false;
4224
+ }
4225
+ if (await this.has(taskId)) {
4226
+ await this.cancel(taskId);
4227
+ }
4228
+ const now = Date.now();
4229
+ const task = {
4230
+ taskId,
4231
+ taskType,
4232
+ payload,
4233
+ assistantId: options.assistantId,
4234
+ threadId: options.threadId,
4235
+ executionType: ScheduleExecutionType2.ONCE,
4236
+ executeAt,
4237
+ delayMs: options.delayMs,
4238
+ status: ScheduledTaskStatus2.PENDING,
4239
+ runCount: 0,
4240
+ retryCount: 0,
4241
+ maxRetries: options.maxRetries ?? 0,
4242
+ createdAt: now,
4243
+ updatedAt: now,
4244
+ metadata: options.metadata
4245
+ };
4246
+ await this.storage.save(task);
4247
+ this.scheduleTimer(task);
4248
+ console.log(
4249
+ `[Scheduler] One-time task scheduled: ${taskId}, executes at ${new Date(
4250
+ executeAt
4251
+ ).toISOString()}`
4252
+ );
4253
+ return true;
4254
+ }
4255
+ // ===== Cron Task Scheduling =====
4256
+ async scheduleCron(taskId, taskType, payload, options) {
4257
+ if (!this.handlers.has(taskType)) {
4258
+ console.error(
4259
+ `[Scheduler] No handler registered for task type: ${taskType}`
4260
+ );
4261
+ return false;
4262
+ }
4263
+ if (!isValidCronExpression(options.cronExpression)) {
4264
+ console.error(
4265
+ `[Scheduler] Invalid cron expression: ${options.cronExpression}`
4266
+ );
4267
+ return false;
4268
+ }
4269
+ if (await this.has(taskId)) {
4270
+ await this.cancel(taskId);
4271
+ }
4272
+ const now = Date.now();
4273
+ const nextRunAt = getNextCronTime(options.cronExpression, new Date(now));
4274
+ const task = {
4275
+ taskId,
4276
+ taskType,
4277
+ payload,
4278
+ assistantId: options.assistantId,
4279
+ threadId: options.threadId,
4280
+ executionType: ScheduleExecutionType2.CRON,
4281
+ cronExpression: options.cronExpression,
4282
+ timezone: options.timezone,
4283
+ nextRunAt: nextRunAt.getTime(),
4284
+ status: ScheduledTaskStatus2.PENDING,
4285
+ runCount: 0,
4286
+ maxRuns: options.maxRuns,
4287
+ retryCount: 0,
4288
+ maxRetries: options.maxRetries ?? 0,
4289
+ createdAt: now,
4290
+ updatedAt: now,
4291
+ expiresAt: options.expiresAt,
4292
+ metadata: options.metadata
4293
+ };
4294
+ await this.storage.save(task);
4295
+ this.scheduleTimer(task);
4296
+ console.log(
4297
+ `[Scheduler] Cron task scheduled: ${taskId}, expression: ${options.cronExpression}, next run: ${nextRunAt.toISOString()}`
4298
+ );
4299
+ return true;
4300
+ }
4301
+ // ===== Task Management =====
4302
+ async cancel(taskId) {
4303
+ const timer = this.timers.get(taskId);
4304
+ if (timer) {
4305
+ clearTimeout(timer.timerId);
4306
+ this.timers.delete(taskId);
4307
+ }
4308
+ const task = await this.storage.get(taskId);
4309
+ if (task) {
4310
+ await this.storage.update(taskId, {
4311
+ status: ScheduledTaskStatus2.CANCELLED
4312
+ });
4313
+ console.log(`[Scheduler] Task cancelled: ${taskId}`);
4314
+ return true;
4315
+ }
4316
+ return false;
4317
+ }
4318
+ async pause(taskId) {
4319
+ const task = await this.storage.get(taskId);
4320
+ if (!task || task.executionType !== ScheduleExecutionType2.CRON) {
4321
+ console.error(`[Scheduler] Can only pause CRON tasks: ${taskId}`);
4322
+ return false;
4323
+ }
4324
+ if (task.status !== ScheduledTaskStatus2.PENDING) {
4325
+ console.error(`[Scheduler] Can only pause PENDING tasks: ${taskId}`);
4326
+ return false;
4327
+ }
4328
+ const timer = this.timers.get(taskId);
4329
+ if (timer) {
4330
+ clearTimeout(timer.timerId);
4331
+ this.timers.delete(taskId);
4332
+ }
4333
+ await this.storage.update(taskId, {
4334
+ status: ScheduledTaskStatus2.PAUSED
4335
+ });
4336
+ console.log(`[Scheduler] Task paused: ${taskId}`);
4337
+ return true;
4338
+ }
4339
+ async resume(taskId) {
4340
+ const task = await this.storage.get(taskId);
4341
+ if (!task || task.executionType !== ScheduleExecutionType2.CRON) {
4342
+ console.error(`[Scheduler] Can only resume CRON tasks: ${taskId}`);
4343
+ return false;
4344
+ }
4345
+ if (task.status !== ScheduledTaskStatus2.PAUSED) {
4346
+ console.error(`[Scheduler] Can only resume PAUSED tasks: ${taskId}`);
4347
+ return false;
4348
+ }
4349
+ const nextRunAt = getNextCronTime(task.cronExpression);
4350
+ await this.storage.update(taskId, {
4351
+ status: ScheduledTaskStatus2.PENDING,
4352
+ nextRunAt: nextRunAt.getTime()
4353
+ });
4354
+ const updatedTask = await this.storage.get(taskId);
4355
+ if (updatedTask) {
4356
+ this.scheduleTimer(updatedTask);
4357
+ }
4358
+ console.log(`[Scheduler] Task resumed: ${taskId}`);
4359
+ return true;
4360
+ }
4361
+ async has(taskId) {
4362
+ const task = await this.storage.get(taskId);
4363
+ return task !== null;
4364
+ }
4365
+ async getTask(taskId) {
4366
+ return this.storage.get(taskId);
4367
+ }
4368
+ async getRemainingTime(taskId) {
4369
+ const task = await this.storage.get(taskId);
4370
+ if (!task) {
4371
+ return -1;
4372
+ }
4373
+ const targetTime = task.executionType === ScheduleExecutionType2.CRON ? task.nextRunAt : task.executeAt;
4374
+ if (targetTime === void 0) {
4375
+ return -1;
4376
+ }
4377
+ return Math.max(0, targetTime - Date.now());
4378
+ }
4379
+ async getActiveTaskCount() {
4380
+ const tasks = await this.storage.getActiveTasks();
4381
+ return tasks.length;
4382
+ }
4383
+ async getActiveTaskIds() {
4384
+ const tasks = await this.storage.getActiveTasks();
4385
+ return tasks.map((t) => t.taskId);
4386
+ }
4387
+ async cancelAll() {
4388
+ for (const timer of this.timers.values()) {
4389
+ clearTimeout(timer.timerId);
4390
+ }
4391
+ this.timers.clear();
4392
+ const activeTasks = await this.storage.getActiveTasks();
4393
+ for (const task of activeTasks) {
4394
+ await this.storage.update(task.taskId, {
4395
+ status: ScheduledTaskStatus2.CANCELLED
4396
+ });
4397
+ }
4398
+ console.log(`[Scheduler] All tasks cancelled`);
4399
+ }
4400
+ // ===== Recovery =====
4401
+ async restore() {
4402
+ const activeTasks = await this.storage.getActiveTasks();
4403
+ let restored = 0;
4404
+ for (const task of activeTasks) {
4405
+ if (!this.handlers.has(task.taskType)) {
4406
+ console.warn(
4407
+ `[Scheduler] No handler for task type ${task.taskType}, skipping restore for task ${task.taskId}`
4408
+ );
4409
+ continue;
4410
+ }
4411
+ if (task.status === ScheduledTaskStatus2.PAUSED) {
4412
+ continue;
4413
+ }
4414
+ if (task.executionType === ScheduleExecutionType2.ONCE) {
4415
+ if (task.executeAt && task.executeAt <= Date.now()) {
4416
+ console.log(
4417
+ `[Scheduler] Executing overdue one-time task: ${task.taskId}`
4418
+ );
4419
+ this.executeTask(task);
4420
+ } else {
4421
+ this.scheduleTimer(task);
4422
+ }
4423
+ } else if (task.executionType === ScheduleExecutionType2.CRON) {
4424
+ const nextRunAt = getNextCronTime(task.cronExpression);
4425
+ await this.storage.update(task.taskId, {
4426
+ nextRunAt: nextRunAt.getTime()
4427
+ });
4428
+ const updatedTask = await this.storage.get(task.taskId);
4429
+ if (updatedTask) {
4430
+ this.scheduleTimer(updatedTask);
4431
+ }
4432
+ }
4433
+ restored++;
4434
+ }
4435
+ console.log(`[Scheduler] Restored ${restored} tasks`);
4436
+ return restored;
4437
+ }
4438
+ // ===== Storage =====
4439
+ setStorage(storage) {
4440
+ this.storage = storage;
4441
+ }
4442
+ getStorage() {
4443
+ return this.storage;
4444
+ }
4445
+ // ===== Private Methods =====
4446
+ scheduleTimer(task) {
4447
+ const targetTime = task.executionType === ScheduleExecutionType2.CRON ? task.nextRunAt : task.executeAt;
4448
+ if (targetTime === void 0) {
4449
+ console.error(`[Scheduler] No execution time for task: ${task.taskId}`);
4450
+ return;
4451
+ }
4452
+ const delay = Math.max(0, targetTime - Date.now());
4453
+ const timerId = setTimeout(() => {
4454
+ this.executeTask(task);
4455
+ }, delay);
4456
+ this.timers.set(task.taskId, {
4457
+ timerId,
4458
+ taskId: task.taskId
4459
+ });
4460
+ }
4461
+ async executeTask(task) {
4462
+ const handler = this.handlers.get(task.taskType);
4463
+ if (!handler) {
4464
+ console.error(
4465
+ `[Scheduler] No handler for task type: ${task.taskType}, task: ${task.taskId}`
4466
+ );
4467
+ await this.storage.update(task.taskId, {
4468
+ status: ScheduledTaskStatus2.FAILED,
4469
+ lastError: `No handler registered for task type: ${task.taskType}`
4470
+ });
4471
+ return;
4472
+ }
4473
+ await this.storage.update(task.taskId, {
4474
+ status: ScheduledTaskStatus2.RUNNING
4475
+ });
4476
+ console.log(`[Scheduler] Executing task: ${task.taskId}`);
4477
+ try {
4478
+ const latestTask = await this.storage.get(task.taskId);
4479
+ if (!latestTask) {
4480
+ console.error(`[Scheduler] Task not found: ${task.taskId}`);
4481
+ return;
4482
+ }
4483
+ await handler(latestTask.payload, latestTask);
4484
+ const newRunCount = latestTask.runCount + 1;
4485
+ console.log(`[Scheduler] Task completed: ${task.taskId}`);
4486
+ if (task.executionType === ScheduleExecutionType2.ONCE) {
4487
+ await this.storage.update(task.taskId, {
4488
+ status: ScheduledTaskStatus2.COMPLETED,
4489
+ runCount: newRunCount,
4490
+ lastRunAt: Date.now()
4491
+ });
4492
+ this.timers.delete(task.taskId);
4493
+ } else if (task.executionType === ScheduleExecutionType2.CRON) {
4494
+ if (task.maxRuns !== void 0 && newRunCount >= task.maxRuns) {
4495
+ await this.storage.update(task.taskId, {
4496
+ status: ScheduledTaskStatus2.COMPLETED,
4497
+ runCount: newRunCount,
4498
+ lastRunAt: Date.now()
4499
+ });
4500
+ this.timers.delete(task.taskId);
4501
+ console.log(
4502
+ `[Scheduler] Cron task completed (max runs): ${task.taskId}`
4503
+ );
4504
+ return;
4505
+ }
4506
+ if (task.expiresAt !== void 0 && Date.now() >= task.expiresAt) {
4507
+ await this.storage.update(task.taskId, {
4508
+ status: ScheduledTaskStatus2.COMPLETED,
4509
+ runCount: newRunCount,
4510
+ lastRunAt: Date.now()
4511
+ });
4512
+ this.timers.delete(task.taskId);
4513
+ console.log(
4514
+ `[Scheduler] Cron task completed (expired): ${task.taskId}`
4515
+ );
4516
+ return;
4517
+ }
4518
+ const nextRunAt = getNextCronTime(task.cronExpression);
4519
+ await this.storage.update(task.taskId, {
4520
+ status: ScheduledTaskStatus2.PENDING,
4521
+ runCount: newRunCount,
4522
+ lastRunAt: Date.now(),
4523
+ nextRunAt: nextRunAt.getTime(),
4524
+ retryCount: 0
4525
+ // Reset retry count on success
4526
+ });
4527
+ const updatedTask = await this.storage.get(task.taskId);
4528
+ if (updatedTask) {
4529
+ this.scheduleTimer(updatedTask);
4530
+ console.log(
4531
+ `[Scheduler] Next cron run scheduled: ${task.taskId} at ${nextRunAt.toISOString()}`
4532
+ );
4533
+ }
4534
+ }
4535
+ } catch (error) {
4536
+ const errorMessage = error instanceof Error ? error.message : String(error);
4537
+ console.error(`[Scheduler] Task failed: ${task.taskId}`, error);
4538
+ const latestTask = await this.storage.get(task.taskId);
4539
+ if (!latestTask) return;
4540
+ const newRetryCount = latestTask.retryCount + 1;
4541
+ if (newRetryCount <= latestTask.maxRetries) {
4542
+ console.log(
4543
+ `[Scheduler] Retrying task: ${task.taskId} (attempt ${newRetryCount}/${latestTask.maxRetries})`
4544
+ );
4545
+ await this.storage.update(task.taskId, {
4546
+ status: ScheduledTaskStatus2.PENDING,
4547
+ retryCount: newRetryCount,
4548
+ lastError: errorMessage
4549
+ });
4550
+ const retryDelay = Math.min(
4551
+ 1e3 * Math.pow(2, newRetryCount - 1),
4552
+ 6e4
4553
+ );
4554
+ const retryTask = await this.storage.get(task.taskId);
4555
+ if (retryTask) {
4556
+ if (task.executionType === ScheduleExecutionType2.ONCE) {
4557
+ retryTask.executeAt = Date.now() + retryDelay;
4558
+ } else {
4559
+ retryTask.nextRunAt = Date.now() + retryDelay;
4560
+ }
4561
+ await this.storage.update(task.taskId, {
4562
+ executeAt: retryTask.executeAt,
4563
+ nextRunAt: retryTask.nextRunAt
4564
+ });
4565
+ this.scheduleTimer(retryTask);
4566
+ }
4567
+ } else {
4568
+ await this.storage.update(task.taskId, {
4569
+ status: ScheduledTaskStatus2.FAILED,
4570
+ retryCount: newRetryCount,
4571
+ lastError: errorMessage
4572
+ });
4573
+ this.timers.delete(task.taskId);
4574
+ console.error(
4575
+ `[Scheduler] Task failed permanently: ${task.taskId} (max retries exceeded)`
4576
+ );
4577
+ }
4578
+ }
4579
+ }
4580
+ };
4581
+ _DefaultScheduleClient.instance = null;
4582
+ var DefaultScheduleClient = _DefaultScheduleClient;
4583
+
4584
+ // src/schedule_lattice/ScheduleLatticeManager.ts
4585
+ var ScheduleLatticeManager = class _ScheduleLatticeManager extends BaseLatticeManager {
4586
+ /**
4587
+ * Get ScheduleLatticeManager singleton instance
4588
+ */
4589
+ static getInstance() {
4590
+ if (!_ScheduleLatticeManager._instance) {
4591
+ _ScheduleLatticeManager._instance = new _ScheduleLatticeManager();
4592
+ }
4593
+ return _ScheduleLatticeManager._instance;
4594
+ }
4595
+ /**
4596
+ * Get Lattice type prefix
4597
+ */
4598
+ getLatticeType() {
4599
+ return "schedules";
4600
+ }
4601
+ /**
4602
+ * Register schedule Lattice
4603
+ * @param key Lattice key name
4604
+ * @param config Schedule configuration
4605
+ * @param client Optional schedule client. If not provided, will create based on config type.
4606
+ */
4607
+ registerLattice(key, config, client) {
4608
+ let scheduleClient;
4609
+ if (client) {
4610
+ scheduleClient = client;
4611
+ if (config.storage) {
4612
+ scheduleClient.setStorage(config.storage);
4613
+ }
4614
+ } else {
4615
+ let storage;
4616
+ if (config.storage) {
4617
+ storage = config.storage;
4618
+ } else {
4619
+ storage = new MemoryScheduleStorage();
4620
+ }
4621
+ if (config.type === ScheduleType.MEMORY) {
4622
+ scheduleClient = new DefaultScheduleClient(storage);
4623
+ } else if (config.type === ScheduleType.POSTGRES) {
4624
+ if (!config.storage) {
4625
+ throw new Error(
4626
+ `PostgreSQL schedule storage must be provided. Please install @axiom-lattice/pg-stores and pass the storage in config.storage.`
4627
+ );
4628
+ }
4629
+ scheduleClient = new DefaultScheduleClient(storage);
4630
+ } else {
4631
+ scheduleClient = new DefaultScheduleClient(storage);
4632
+ }
4633
+ }
4634
+ const scheduleLattice = {
4635
+ key,
4636
+ config,
4637
+ client: scheduleClient,
4638
+ // Handler registration
4639
+ registerHandler: (taskType, handler) => {
4640
+ scheduleClient.registerHandler(taskType, handler);
4641
+ },
4642
+ unregisterHandler: (taskType) => {
4643
+ return scheduleClient.unregisterHandler(taskType);
4644
+ },
4645
+ hasHandler: (taskType) => {
4646
+ return scheduleClient.hasHandler(taskType);
4647
+ },
4648
+ getHandlerTypes: () => {
4649
+ return scheduleClient.getHandlerTypes();
4650
+ },
4651
+ // One-time task scheduling
4652
+ scheduleOnce: async (taskId, taskType, payload, options) => {
4653
+ return scheduleClient.scheduleOnce(taskId, taskType, payload, options);
4654
+ },
4655
+ // Cron task scheduling
4656
+ scheduleCron: async (taskId, taskType, payload, options) => {
4657
+ return scheduleClient.scheduleCron(taskId, taskType, payload, options);
4658
+ },
4659
+ // Task management
4660
+ cancel: async (taskId) => {
4661
+ return scheduleClient.cancel(taskId);
4662
+ },
4663
+ pause: async (taskId) => {
4664
+ return scheduleClient.pause(taskId);
4665
+ },
4666
+ resume: async (taskId) => {
4667
+ return scheduleClient.resume(taskId);
4668
+ },
4669
+ has: async (taskId) => {
4670
+ return scheduleClient.has(taskId);
4671
+ },
4672
+ getTask: async (taskId) => {
4673
+ return scheduleClient.getTask(taskId);
4674
+ },
4675
+ getRemainingTime: async (taskId) => {
4676
+ return scheduleClient.getRemainingTime(taskId);
4677
+ },
4678
+ getActiveTaskCount: async () => {
4679
+ return scheduleClient.getActiveTaskCount();
4680
+ },
4681
+ getActiveTaskIds: async () => {
4682
+ return scheduleClient.getActiveTaskIds();
4683
+ },
4684
+ cancelAll: async () => {
4685
+ return scheduleClient.cancelAll();
4686
+ },
4687
+ // Recovery
4688
+ restore: async () => {
4689
+ return scheduleClient.restore();
4690
+ }
4691
+ };
4692
+ this.register(key, scheduleLattice);
4693
+ }
4694
+ /**
4695
+ * Get ScheduleLattice
4696
+ * @param key Lattice key name
4697
+ */
4698
+ getScheduleLattice(key) {
4699
+ const scheduleLattice = this.get(key);
4700
+ if (!scheduleLattice) {
4701
+ throw new Error(`ScheduleLattice ${key} not found`);
4702
+ }
4703
+ return scheduleLattice;
4704
+ }
4705
+ /**
4706
+ * Get all Lattices
4707
+ */
4708
+ getAllLattices() {
4709
+ return this.getAll();
4710
+ }
4711
+ /**
4712
+ * Check if Lattice exists
4713
+ * @param key Lattice key name
4714
+ */
4715
+ hasLattice(key) {
4716
+ return this.has(key);
4717
+ }
4718
+ /**
4719
+ * Remove Lattice
4720
+ * @param key Lattice key name
4721
+ */
4722
+ removeLattice(key) {
4723
+ return this.remove(key);
4724
+ }
4725
+ /**
4726
+ * Clear all Lattices
4727
+ */
4728
+ clearLattices() {
4729
+ this.clear();
4730
+ }
4731
+ /**
4732
+ * Get Lattice count
4733
+ */
4734
+ getLatticeCount() {
4735
+ return this.count();
4736
+ }
4737
+ /**
4738
+ * Get Lattice key list
4739
+ */
4740
+ getLatticeKeys() {
4741
+ return this.keys();
4742
+ }
4743
+ };
4744
+ var scheduleLatticeManager = ScheduleLatticeManager.getInstance();
4745
+ var registerScheduleLattice = (key, config, client) => scheduleLatticeManager.registerLattice(key, config, client);
4746
+ var getScheduleLattice = (key) => scheduleLatticeManager.getScheduleLattice(key);
4747
+
3229
4748
  // src/store_lattice/InMemoryThreadStore.ts
3230
4749
  var InMemoryThreadStore = class {
3231
4750
  constructor() {
@@ -3728,6 +5247,7 @@ export {
3728
5247
  AgentType,
3729
5248
  ChunkBuffer,
3730
5249
  ChunkBufferLatticeManager,
5250
+ DefaultScheduleClient,
3731
5251
  EmbeddingsLatticeManager,
3732
5252
  GraphBuildOptions,
3733
5253
  InMemoryAssistantStore,
@@ -3735,15 +5255,20 @@ export {
3735
5255
  InMemoryThreadStore,
3736
5256
  MemoryLatticeManager,
3737
5257
  MemoryQueueClient,
5258
+ MemoryScheduleStorage,
3738
5259
  MemoryType,
3739
5260
  ModelLatticeManager,
5261
+ PostgresDatabase,
3740
5262
  Protocols,
3741
5263
  QueueLatticeManager,
5264
+ ScheduleLatticeManager,
5265
+ SqlDatabaseManager,
3742
5266
  StoreLatticeManager,
3743
5267
  ThreadStatus,
3744
5268
  ToolLatticeManager,
3745
5269
  VectorStoreLatticeManager,
3746
5270
  agentLatticeManager,
5271
+ describeCronExpression,
3747
5272
  embeddingsLatticeManager,
3748
5273
  eventBus,
3749
5274
  event_bus_default as eventBusDefault,
@@ -3757,7 +5282,9 @@ export {
3757
5282
  getEmbeddingsClient,
3758
5283
  getEmbeddingsLattice,
3759
5284
  getModelLattice,
5285
+ getNextCronTime,
3760
5286
  getQueueLattice,
5287
+ getScheduleLattice,
3761
5288
  getStoreLattice,
3762
5289
  getToolClient,
3763
5290
  getToolDefinition,
@@ -3765,7 +5292,9 @@ export {
3765
5292
  getVectorStoreClient,
3766
5293
  getVectorStoreLattice,
3767
5294
  hasChunkBuffer,
5295
+ isValidCronExpression,
3768
5296
  modelLatticeManager,
5297
+ parseCronExpression,
3769
5298
  queueLatticeManager,
3770
5299
  registerAgentLattice,
3771
5300
  registerAgentLattices,
@@ -3774,9 +5303,12 @@ export {
3774
5303
  registerEmbeddingsLattice,
3775
5304
  registerModelLattice,
3776
5305
  registerQueueLattice,
5306
+ registerScheduleLattice,
3777
5307
  registerStoreLattice,
3778
5308
  registerToolLattice,
3779
5309
  registerVectorStoreLattice,
5310
+ scheduleLatticeManager,
5311
+ sqlDatabaseManager,
3780
5312
  storeLatticeManager,
3781
5313
  toolLatticeManager,
3782
5314
  validateAgentInput,