@axiom-lattice/core 2.1.13 → 2.1.15

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
  );
@@ -3231,200 +3763,931 @@ import {
3231
3763
  ScheduleType
3232
3764
  } from "@axiom-lattice/protocols";
3233
3765
 
3234
- // src/schedule_lattice/MemoryScheduleClient.ts
3235
- var _MemoryScheduleClient = class _MemoryScheduleClient {
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 {
3236
3777
  constructor() {
3237
3778
  this.tasks = /* @__PURE__ */ new Map();
3238
3779
  }
3239
3780
  /**
3240
- * Get the singleton instance of MemoryScheduleClient
3781
+ * Save a new task
3241
3782
  */
3242
- static getInstance() {
3243
- if (!_MemoryScheduleClient.instance) {
3244
- _MemoryScheduleClient.instance = new _MemoryScheduleClient();
3245
- }
3246
- return _MemoryScheduleClient.instance;
3783
+ async save(task) {
3784
+ this.tasks.set(task.taskId, { ...task });
3247
3785
  }
3248
3786
  /**
3249
- * Register a function to be executed after the specified timeout
3250
- * @param taskId - Unique identifier for the task
3251
- * @param callback - Function to execute when timeout expires
3252
- * @param timeoutMs - Delay in milliseconds before execution
3253
- * @returns true if registered successfully
3787
+ * Get task by ID
3254
3788
  */
3255
- register(taskId, callback, timeoutMs) {
3256
- if (this.tasks.has(taskId)) {
3257
- this.cancel(taskId);
3258
- }
3259
- const timerId = setTimeout(async () => {
3260
- try {
3261
- console.log("scheduler callback", taskId, "start");
3262
- await callback();
3263
- console.log("scheduler callback", taskId, "success");
3264
- } catch (error) {
3265
- console.error(`Scheduler: Error executing task "${taskId}":`, error);
3266
- } finally {
3267
- this.tasks.delete(taskId);
3268
- console.log("scheduler callback", taskId, "end");
3269
- }
3270
- }, timeoutMs);
3271
- this.tasks.set(taskId, {
3272
- timerId,
3273
- callback,
3274
- scheduledAt: Date.now(),
3275
- timeoutMs
3276
- });
3277
- console.log("scheduler register", taskId);
3278
- return true;
3789
+ async get(taskId) {
3790
+ const task = this.tasks.get(taskId);
3791
+ return task ? { ...task } : null;
3279
3792
  }
3280
3793
  /**
3281
- * Cancel a scheduled task by its ID
3282
- * @param taskId - The task identifier to cancel
3283
- * @returns true if task was found and cancelled, false otherwise
3794
+ * Update task
3284
3795
  */
3285
- cancel(taskId) {
3286
- console.log("scheduler cancel", taskId);
3796
+ async update(taskId, updates) {
3287
3797
  const task = this.tasks.get(taskId);
3288
3798
  if (task) {
3289
- clearTimeout(task.timerId);
3290
- this.tasks.delete(taskId);
3291
- return true;
3799
+ this.tasks.set(taskId, {
3800
+ ...task,
3801
+ ...updates,
3802
+ updatedAt: Date.now()
3803
+ });
3292
3804
  }
3293
- return false;
3294
3805
  }
3295
3806
  /**
3296
- * Check if a task is currently scheduled
3297
- * @param taskId - The task identifier to check
3807
+ * Delete task
3298
3808
  */
3299
- has(taskId) {
3300
- return this.tasks.has(taskId);
3809
+ async delete(taskId) {
3810
+ this.tasks.delete(taskId);
3301
3811
  }
3302
3812
  /**
3303
- * Get the remaining time in milliseconds for a scheduled task
3304
- * @param taskId - The task identifier
3305
- * @returns Remaining time in ms, or -1 if task not found
3813
+ * Get all active tasks (pending or paused)
3306
3814
  */
3307
- getRemainingTime(taskId) {
3308
- const task = this.tasks.get(taskId);
3309
- if (!task) {
3310
- return -1;
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
+ }
3311
3821
  }
3312
- const elapsed = Date.now() - task.scheduledAt;
3313
- return Math.max(0, task.timeoutMs - elapsed);
3822
+ return result;
3314
3823
  }
3315
3824
  /**
3316
- * Get the count of currently scheduled tasks
3825
+ * Get tasks by type
3317
3826
  */
3318
- getTaskCount() {
3319
- return this.tasks.size;
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;
3320
3835
  }
3321
3836
  /**
3322
- * Get all scheduled task IDs
3837
+ * Get tasks by status
3323
3838
  */
3324
- getTaskIds() {
3325
- return Array.from(this.tasks.keys());
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;
3326
3847
  }
3327
3848
  /**
3328
- * Cancel all scheduled tasks
3849
+ * Get tasks by execution type
3329
3850
  */
3330
- cancelAll() {
3331
- for (const [taskId, task] of this.tasks) {
3332
- clearTimeout(task.timerId);
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
+ }
3333
3857
  }
3334
- this.tasks.clear();
3858
+ return result;
3335
3859
  }
3336
3860
  /**
3337
- * Get task information
3338
- * @param taskId - The task identifier
3339
- * @returns Task info or null if not found
3861
+ * Get tasks by assistant ID
3340
3862
  */
3341
- getTaskInfo(taskId) {
3342
- const task = this.tasks.get(taskId);
3343
- if (!task) {
3344
- return null;
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
+ }
3345
3869
  }
3346
- return {
3347
- taskId,
3348
- scheduledAt: task.scheduledAt,
3349
- timeoutMs: task.timeoutMs,
3350
- remainingMs: this.getRemainingTime(taskId)
3351
- };
3870
+ return result;
3352
3871
  }
3353
3872
  /**
3354
- * Reset the singleton instance (useful for testing)
3873
+ * Get tasks by thread ID
3355
3874
  */
3356
- static resetInstance() {
3357
- if (_MemoryScheduleClient.instance) {
3358
- _MemoryScheduleClient.instance.cancelAll();
3359
- _MemoryScheduleClient.instance = null;
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
+ }
3360
3881
  }
3882
+ return result;
3361
3883
  }
3362
- };
3363
- _MemoryScheduleClient.instance = null;
3364
- var MemoryScheduleClient = _MemoryScheduleClient;
3365
-
3366
- // src/schedule_lattice/ScheduleLatticeManager.ts
3367
- var ScheduleLatticeManager = class _ScheduleLatticeManager extends BaseLatticeManager {
3368
3884
  /**
3369
- * Get ScheduleLatticeManager singleton instance
3885
+ * Get all tasks with optional filters
3370
3886
  */
3371
- static getInstance() {
3372
- if (!_ScheduleLatticeManager._instance) {
3373
- _ScheduleLatticeManager._instance = new _ScheduleLatticeManager();
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
+ }
3374
3909
  }
3375
- return _ScheduleLatticeManager._instance;
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;
3376
3919
  }
3377
3920
  /**
3378
- * Get Lattice type prefix
3921
+ * Count tasks with optional filters
3379
3922
  */
3380
- getLatticeType() {
3381
- return "schedules";
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;
3382
3947
  }
3383
3948
  /**
3384
- * Register schedule Lattice
3385
- * @param key Lattice key name
3386
- * @param config Schedule configuration
3387
- * @param client Optional schedule client. If not provided, will create based on config type.
3949
+ * Delete completed/cancelled tasks older than specified time
3388
3950
  */
3389
- registerLattice(key, config, client) {
3390
- let scheduleClient;
3391
- if (client) {
3392
- scheduleClient = client;
3393
- } else {
3394
- if (config.type === ScheduleType.MEMORY) {
3395
- scheduleClient = MemoryScheduleClient.getInstance();
3396
- } else {
3397
- scheduleClient = MemoryScheduleClient.getInstance();
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++;
3398
3958
  }
3399
3959
  }
3400
- const scheduleLattice = {
3401
- key,
3402
- config,
3403
- client: scheduleClient,
3404
- register: (taskId, callback, timeoutMs) => {
3405
- return scheduleClient.register(taskId, callback, timeoutMs);
3406
- },
3407
- cancel: (taskId) => {
3408
- return scheduleClient.cancel(taskId);
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);
3409
4641
  },
3410
- has: (taskId) => {
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) => {
3411
4670
  return scheduleClient.has(taskId);
3412
4671
  },
3413
- getRemainingTime: (taskId) => {
4672
+ getTask: async (taskId) => {
4673
+ return scheduleClient.getTask(taskId);
4674
+ },
4675
+ getRemainingTime: async (taskId) => {
3414
4676
  return scheduleClient.getRemainingTime(taskId);
3415
4677
  },
3416
- getTaskCount: () => {
3417
- return scheduleClient.getTaskCount();
4678
+ getActiveTaskCount: async () => {
4679
+ return scheduleClient.getActiveTaskCount();
3418
4680
  },
3419
- getTaskIds: () => {
3420
- return scheduleClient.getTaskIds();
4681
+ getActiveTaskIds: async () => {
4682
+ return scheduleClient.getActiveTaskIds();
3421
4683
  },
3422
- cancelAll: () => {
4684
+ cancelAll: async () => {
3423
4685
  return scheduleClient.cancelAll();
3424
4686
  },
3425
- getTaskInfo: scheduleClient.getTaskInfo ? (taskId) => {
3426
- return scheduleClient.getTaskInfo(taskId);
3427
- } : void 0
4687
+ // Recovery
4688
+ restore: async () => {
4689
+ return scheduleClient.restore();
4690
+ }
3428
4691
  };
3429
4692
  this.register(key, scheduleLattice);
3430
4693
  }
@@ -3974,6 +5237,323 @@ var registerVectorStoreLattice = (key, vectorStore) => vectorStoreLatticeManager
3974
5237
  var getVectorStoreLattice = (key) => vectorStoreLatticeManager.getVectorStoreLattice(key);
3975
5238
  var getVectorStoreClient = (key) => vectorStoreLatticeManager.getVectorStoreClient(key);
3976
5239
 
5240
+ // src/logger_lattice/LoggerLatticeManager.ts
5241
+ import {
5242
+ LoggerType
5243
+ } from "@axiom-lattice/protocols";
5244
+
5245
+ // src/logger_lattice/PinoLoggerClient.ts
5246
+ import pino from "pino";
5247
+ import "pino-pretty";
5248
+ import "pino-roll";
5249
+ var PinoLoggerClient = class _PinoLoggerClient {
5250
+ constructor(config) {
5251
+ this.config = config;
5252
+ this.context = config.context || {};
5253
+ const loggerConfig = {
5254
+ // Custom timestamp format
5255
+ timestamp: () => `,"@timestamp":"${(/* @__PURE__ */ new Date()).toISOString()}"`,
5256
+ // Base metadata
5257
+ base: {
5258
+ "@version": "1",
5259
+ app_name: "lattice",
5260
+ service_name: config.serviceName || "lattice-service",
5261
+ thread_name: "main",
5262
+ logger_name: config.loggerName || config.name || "lattice-logger"
5263
+ },
5264
+ formatters: {
5265
+ level: (label, number) => {
5266
+ return {
5267
+ level: label.toUpperCase(),
5268
+ level_value: number * 1e3
5269
+ };
5270
+ }
5271
+ }
5272
+ };
5273
+ const useFileLogging = this.shouldUseFileLogging(config);
5274
+ const fileOptions = this.getFileOptions(config);
5275
+ if (useFileLogging && fileOptions) {
5276
+ try {
5277
+ this.pinoLogger = pino(
5278
+ loggerConfig,
5279
+ pino.transport({
5280
+ target: "pino-roll",
5281
+ options: {
5282
+ file: fileOptions.file || "./logs/app",
5283
+ frequency: fileOptions.frequency || "daily",
5284
+ mkdir: fileOptions.mkdir !== false,
5285
+ // Default to true
5286
+ size: fileOptions.size,
5287
+ maxFiles: fileOptions.maxFiles
5288
+ }
5289
+ })
5290
+ );
5291
+ } catch (error) {
5292
+ console.error(
5293
+ "Failed to initialize pino-roll logger, falling back to console",
5294
+ error
5295
+ );
5296
+ this.pinoLogger = pino({
5297
+ ...loggerConfig,
5298
+ transport: {
5299
+ target: "pino-pretty",
5300
+ options: {
5301
+ colorize: true
5302
+ }
5303
+ }
5304
+ });
5305
+ }
5306
+ } else {
5307
+ this.pinoLogger = pino({
5308
+ ...loggerConfig,
5309
+ transport: {
5310
+ target: "pino-pretty",
5311
+ options: {
5312
+ colorize: true
5313
+ }
5314
+ }
5315
+ });
5316
+ }
5317
+ }
5318
+ /**
5319
+ * Determine if file logging should be used
5320
+ */
5321
+ shouldUseFileLogging(config) {
5322
+ const hasFileConfig = config.file !== void 0;
5323
+ const isProduction = process.env.NODE_ENV === "production";
5324
+ return hasFileConfig || isProduction;
5325
+ }
5326
+ /**
5327
+ * Get file options from config
5328
+ */
5329
+ getFileOptions(config) {
5330
+ if (!config.file) {
5331
+ if (process.env.NODE_ENV === "production") {
5332
+ return {
5333
+ file: "./logs/app",
5334
+ frequency: "daily",
5335
+ mkdir: true
5336
+ };
5337
+ }
5338
+ return null;
5339
+ }
5340
+ if (typeof config.file === "string") {
5341
+ return {
5342
+ file: config.file,
5343
+ frequency: "daily",
5344
+ mkdir: true
5345
+ };
5346
+ }
5347
+ return config.file;
5348
+ }
5349
+ /**
5350
+ * Get contextual logger with merged context
5351
+ */
5352
+ getContextualLogger(additionalContext) {
5353
+ const contextObj = {
5354
+ "x-user-id": this.context["x-user-id"] || "",
5355
+ "x-tenant-id": this.context["x-tenant-id"] || "",
5356
+ "x-request-id": this.context["x-request-id"] || "",
5357
+ "x-thread-id": this.context["x-thread-id"] || "",
5358
+ service_name: this.config.serviceName || "lattice-service",
5359
+ logger_name: this.config.loggerName || this.config.name || "lattice-logger",
5360
+ ...additionalContext
5361
+ };
5362
+ return this.pinoLogger.child(contextObj);
5363
+ }
5364
+ info(msg, obj) {
5365
+ this.getContextualLogger(obj).info(msg);
5366
+ }
5367
+ error(msg, obj) {
5368
+ this.getContextualLogger(obj).error(msg);
5369
+ }
5370
+ warn(msg, obj) {
5371
+ this.getContextualLogger(obj).warn(msg);
5372
+ }
5373
+ debug(msg, obj) {
5374
+ this.getContextualLogger(obj).debug(msg);
5375
+ }
5376
+ updateContext(context) {
5377
+ this.context = {
5378
+ ...this.context,
5379
+ ...context
5380
+ };
5381
+ }
5382
+ child(options) {
5383
+ return new _PinoLoggerClient({
5384
+ ...this.config,
5385
+ ...options,
5386
+ context: {
5387
+ ...this.context,
5388
+ ...options.context
5389
+ }
5390
+ });
5391
+ }
5392
+ };
5393
+
5394
+ // src/logger_lattice/ConsoleLoggerClient.ts
5395
+ var ConsoleLoggerClient = class _ConsoleLoggerClient {
5396
+ constructor(config) {
5397
+ this.config = config;
5398
+ this.context = config.context || {};
5399
+ }
5400
+ formatMessage(level, msg, obj) {
5401
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
5402
+ const contextStr = Object.keys(this.context).length > 0 ? ` [${JSON.stringify(this.context)}]` : "";
5403
+ const objStr = obj ? ` ${JSON.stringify(obj)}` : "";
5404
+ return `[${timestamp}] [${level}]${contextStr} ${msg}${objStr}`;
5405
+ }
5406
+ info(msg, obj) {
5407
+ console.log(this.formatMessage("INFO", msg, obj));
5408
+ }
5409
+ error(msg, obj) {
5410
+ console.error(this.formatMessage("ERROR", msg, obj));
5411
+ }
5412
+ warn(msg, obj) {
5413
+ console.warn(this.formatMessage("WARN", msg, obj));
5414
+ }
5415
+ debug(msg, obj) {
5416
+ console.debug(this.formatMessage("DEBUG", msg, obj));
5417
+ }
5418
+ updateContext(context) {
5419
+ this.context = {
5420
+ ...this.context,
5421
+ ...context
5422
+ };
5423
+ }
5424
+ child(options) {
5425
+ const childClient = new _ConsoleLoggerClient({
5426
+ ...this.config,
5427
+ ...options,
5428
+ context: {
5429
+ ...this.context,
5430
+ ...options.context
5431
+ }
5432
+ });
5433
+ return childClient;
5434
+ }
5435
+ };
5436
+
5437
+ // src/logger_lattice/LoggerLatticeManager.ts
5438
+ var LoggerLatticeManager = class _LoggerLatticeManager extends BaseLatticeManager {
5439
+ /**
5440
+ * Get LoggerLatticeManager singleton instance
5441
+ */
5442
+ static getInstance() {
5443
+ if (!_LoggerLatticeManager._instance) {
5444
+ _LoggerLatticeManager._instance = new _LoggerLatticeManager();
5445
+ }
5446
+ return _LoggerLatticeManager._instance;
5447
+ }
5448
+ /**
5449
+ * Get Lattice type prefix
5450
+ */
5451
+ getLatticeType() {
5452
+ return "loggers";
5453
+ }
5454
+ /**
5455
+ * Register logger Lattice
5456
+ * @param key Lattice key name
5457
+ * @param config Logger configuration
5458
+ * @param client Optional logger client. If not provided, will create based on config type.
5459
+ */
5460
+ registerLattice(key, config, client) {
5461
+ let loggerClient;
5462
+ if (client) {
5463
+ loggerClient = client;
5464
+ } else {
5465
+ if (config.type === LoggerType.PINO) {
5466
+ loggerClient = new PinoLoggerClient(config);
5467
+ } else if (config.type === LoggerType.CONSOLE) {
5468
+ loggerClient = new ConsoleLoggerClient(config);
5469
+ } else if (config.type === LoggerType.CUSTOM) {
5470
+ throw new Error(
5471
+ `Custom logger client must be provided. Please pass the client to registerLattice.`
5472
+ );
5473
+ } else {
5474
+ loggerClient = new PinoLoggerClient(config);
5475
+ }
5476
+ }
5477
+ const loggerLattice = {
5478
+ key,
5479
+ config,
5480
+ client: loggerClient,
5481
+ // Logger operations
5482
+ info: (msg, obj) => {
5483
+ loggerClient.info(msg, obj);
5484
+ },
5485
+ error: (msg, obj) => {
5486
+ loggerClient.error(msg, obj);
5487
+ },
5488
+ warn: (msg, obj) => {
5489
+ loggerClient.warn(msg, obj);
5490
+ },
5491
+ debug: (msg, obj) => {
5492
+ loggerClient.debug(msg, obj);
5493
+ },
5494
+ updateContext: loggerClient.updateContext ? (context) => {
5495
+ loggerClient.updateContext(context);
5496
+ } : void 0,
5497
+ child: loggerClient.child ? (options) => {
5498
+ return loggerClient.child(options);
5499
+ } : void 0
5500
+ };
5501
+ this.register(key, loggerLattice);
5502
+ }
5503
+ /**
5504
+ * Get LoggerLattice
5505
+ * @param key Lattice key name
5506
+ */
5507
+ getLoggerLattice(key) {
5508
+ const loggerLattice = this.get(key);
5509
+ if (!loggerLattice) {
5510
+ throw new Error(`LoggerLattice ${key} not found`);
5511
+ }
5512
+ return loggerLattice;
5513
+ }
5514
+ /**
5515
+ * Get all Lattices
5516
+ */
5517
+ getAllLattices() {
5518
+ return this.getAll();
5519
+ }
5520
+ /**
5521
+ * Check if Lattice exists
5522
+ * @param key Lattice key name
5523
+ */
5524
+ hasLattice(key) {
5525
+ return this.has(key);
5526
+ }
5527
+ /**
5528
+ * Remove Lattice
5529
+ * @param key Lattice key name
5530
+ */
5531
+ removeLattice(key) {
5532
+ return this.remove(key);
5533
+ }
5534
+ /**
5535
+ * Clear all Lattices
5536
+ */
5537
+ clearLattices() {
5538
+ this.clear();
5539
+ }
5540
+ /**
5541
+ * Get Lattice count
5542
+ */
5543
+ getLatticeCount() {
5544
+ return this.count();
5545
+ }
5546
+ /**
5547
+ * Get Lattice key list
5548
+ */
5549
+ getLatticeKeys() {
5550
+ return this.keys();
5551
+ }
5552
+ };
5553
+ var loggerLatticeManager = LoggerLatticeManager.getInstance();
5554
+ var registerLoggerLattice = (key, config, client) => loggerLatticeManager.registerLattice(key, config, client);
5555
+ var getLoggerLattice = (key) => loggerLatticeManager.getLoggerLattice(key);
5556
+
3977
5557
  // src/index.ts
3978
5558
  import * as Protocols from "@axiom-lattice/protocols";
3979
5559
  export {
@@ -3984,24 +5564,31 @@ export {
3984
5564
  AgentType,
3985
5565
  ChunkBuffer,
3986
5566
  ChunkBufferLatticeManager,
5567
+ ConsoleLoggerClient,
5568
+ DefaultScheduleClient,
3987
5569
  EmbeddingsLatticeManager,
3988
5570
  GraphBuildOptions,
3989
5571
  InMemoryAssistantStore,
3990
5572
  InMemoryChunkBuffer,
3991
5573
  InMemoryThreadStore,
5574
+ LoggerLatticeManager,
3992
5575
  MemoryLatticeManager,
3993
5576
  MemoryQueueClient,
3994
- MemoryScheduleClient,
5577
+ MemoryScheduleStorage,
3995
5578
  MemoryType,
3996
5579
  ModelLatticeManager,
5580
+ PinoLoggerClient,
5581
+ PostgresDatabase,
3997
5582
  Protocols,
3998
5583
  QueueLatticeManager,
3999
5584
  ScheduleLatticeManager,
5585
+ SqlDatabaseManager,
4000
5586
  StoreLatticeManager,
4001
5587
  ThreadStatus,
4002
5588
  ToolLatticeManager,
4003
5589
  VectorStoreLatticeManager,
4004
5590
  agentLatticeManager,
5591
+ describeCronExpression,
4005
5592
  embeddingsLatticeManager,
4006
5593
  eventBus,
4007
5594
  event_bus_default as eventBusDefault,
@@ -4014,7 +5601,9 @@ export {
4014
5601
  getChunkBuffer,
4015
5602
  getEmbeddingsClient,
4016
5603
  getEmbeddingsLattice,
5604
+ getLoggerLattice,
4017
5605
  getModelLattice,
5606
+ getNextCronTime,
4018
5607
  getQueueLattice,
4019
5608
  getScheduleLattice,
4020
5609
  getStoreLattice,
@@ -4024,13 +5613,17 @@ export {
4024
5613
  getVectorStoreClient,
4025
5614
  getVectorStoreLattice,
4026
5615
  hasChunkBuffer,
5616
+ isValidCronExpression,
5617
+ loggerLatticeManager,
4027
5618
  modelLatticeManager,
5619
+ parseCronExpression,
4028
5620
  queueLatticeManager,
4029
5621
  registerAgentLattice,
4030
5622
  registerAgentLattices,
4031
5623
  registerCheckpointSaver,
4032
5624
  registerChunkBuffer,
4033
5625
  registerEmbeddingsLattice,
5626
+ registerLoggerLattice,
4034
5627
  registerModelLattice,
4035
5628
  registerQueueLattice,
4036
5629
  registerScheduleLattice,
@@ -4038,6 +5631,7 @@ export {
4038
5631
  registerToolLattice,
4039
5632
  registerVectorStoreLattice,
4040
5633
  scheduleLatticeManager,
5634
+ sqlDatabaseManager,
4041
5635
  storeLatticeManager,
4042
5636
  toolLatticeManager,
4043
5637
  validateAgentInput,