@agentforge/core 0.18.7 → 0.18.9

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.
Files changed (3) hide show
  1. package/dist/index.cjs +113 -113
  2. package/dist/index.js +106 -106
  3. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -1245,6 +1245,47 @@ function snapshotExecutionMetrics(metrics) {
1245
1245
  };
1246
1246
  }
1247
1247
 
1248
+ // src/tools/execution-resilience.ts
1249
+ function normalizeThrownValue(error) {
1250
+ return error instanceof Error ? error : new Error(String(error));
1251
+ }
1252
+ async function executeWithRetries(execute, maxAttempts, retryDelay, shouldRetry) {
1253
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1254
+ try {
1255
+ return await execute();
1256
+ } catch (thrownValue) {
1257
+ const error = normalizeThrownValue(thrownValue);
1258
+ if (attempt === maxAttempts || !shouldRetry(error)) {
1259
+ throw error;
1260
+ }
1261
+ await new Promise((resolve) => setTimeout(resolve, retryDelay(attempt, error)));
1262
+ }
1263
+ }
1264
+ throw new Error("Retry execution requires at least one attempt");
1265
+ }
1266
+ async function executeWithTimeout(execute, timeoutMs, timeoutError, startOrder = "timeout-first") {
1267
+ let timeoutId;
1268
+ const startTimeout = () => new Promise((_, reject) => {
1269
+ timeoutId = setTimeout(() => reject(timeoutError()), timeoutMs);
1270
+ });
1271
+ try {
1272
+ let executionPromise;
1273
+ let timeoutPromise;
1274
+ if (startOrder === "execution-first") {
1275
+ executionPromise = execute();
1276
+ timeoutPromise = startTimeout();
1277
+ } else {
1278
+ timeoutPromise = startTimeout();
1279
+ executionPromise = execute();
1280
+ }
1281
+ return await Promise.race([executionPromise, timeoutPromise]);
1282
+ } finally {
1283
+ if (timeoutId !== void 0) {
1284
+ clearTimeout(timeoutId);
1285
+ }
1286
+ }
1287
+ }
1288
+
1248
1289
  // src/tools/executor-retry.ts
1249
1290
  function calculateBackoff(attempt, policy) {
1250
1291
  const initialDelay = policy.initialDelay || 1e3;
@@ -1264,10 +1305,7 @@ function calculateBackoff(attempt, policy) {
1264
1305
  return Math.min(delay, maxDelay);
1265
1306
  }
1266
1307
  function toError(error) {
1267
- if (error instanceof Error) {
1268
- return error;
1269
- }
1270
- return new Error(String(error));
1308
+ return normalizeThrownValue(error);
1271
1309
  }
1272
1310
  function resolveExecutionMethod(tool, logger6) {
1273
1311
  const executeFn = tool.invoke || tool.execute;
@@ -1293,28 +1331,20 @@ async function executeWithRetry(tool, input, policy, logger6) {
1293
1331
  `Invalid retry policy: maxAttempts must be an integer >= 1 (received ${String(policy.maxAttempts)})`
1294
1332
  );
1295
1333
  }
1296
- let lastError;
1297
- for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
1298
- try {
1299
- return await executeFn.call(tool, input);
1300
- } catch (error) {
1301
- const currentError = toError(error);
1302
- lastError = currentError;
1303
- if (policy.retryableErrors && policy.retryableErrors.length > 0) {
1304
- const isRetryable = policy.retryableErrors.some(
1305
- (message) => currentError.message.includes(message)
1306
- );
1307
- if (!isRetryable) {
1308
- throw currentError;
1309
- }
1310
- }
1311
- if (attempt < policy.maxAttempts) {
1312
- const delay = calculateBackoff(attempt, policy);
1313
- await new Promise((resolve) => setTimeout(resolve, delay));
1314
- }
1315
- }
1316
- }
1317
- throw lastError ?? new Error("Tool execution failed after retries");
1334
+ return executeWithRetries(
1335
+ () => executeFn.call(tool, input),
1336
+ policy.maxAttempts,
1337
+ (attempt) => calculateBackoff(attempt, policy),
1338
+ (error) => !policy.retryableErrors?.length || policy.retryableErrors.some((message) => error.message.includes(message))
1339
+ );
1340
+ }
1341
+ async function executeWithTimeout2(execute, timeout2) {
1342
+ return executeWithTimeout(
1343
+ execute,
1344
+ timeout2,
1345
+ () => new Error("Tool execution timeout"),
1346
+ "execution-first"
1347
+ );
1318
1348
  }
1319
1349
 
1320
1350
  // src/tools/executor-types.ts
@@ -1342,15 +1372,12 @@ function createToolExecutor(config = {}) {
1342
1372
  const metrics = createExecutionMetrics();
1343
1373
  async function executeSingle(tool, input, priority) {
1344
1374
  const startTime = Date.now();
1345
- let timeoutId;
1346
1375
  try {
1347
1376
  onExecutionStart?.(tool, input);
1348
- const result = await Promise.race([
1349
- executeWithRetry(tool, input, retryPolicy, logger2),
1350
- new Promise((_, reject) => {
1351
- timeoutId = setTimeout(() => reject(new Error("Tool execution timeout")), timeout2);
1352
- })
1353
- ]);
1377
+ const result = await executeWithTimeout2(
1378
+ () => executeWithRetry(tool, input, retryPolicy, logger2),
1379
+ timeout2
1380
+ );
1354
1381
  const duration = Date.now() - startTime;
1355
1382
  recordExecutionResult(metrics, priority, duration, true);
1356
1383
  onExecutionComplete?.(tool, input, result, duration);
@@ -1361,10 +1388,6 @@ function createToolExecutor(config = {}) {
1361
1388
  recordExecutionResult(metrics, priority, duration, false);
1362
1389
  onExecutionError?.(tool, input, normalizedError, duration);
1363
1390
  throw normalizedError;
1364
- } finally {
1365
- if (timeoutId) {
1366
- clearTimeout(timeoutId);
1367
- }
1368
1391
  }
1369
1392
  }
1370
1393
  function processQueue() {
@@ -1739,9 +1762,6 @@ function isConditionalStep(step) {
1739
1762
  function calculateRetryDelay(attempt, delay, backoff) {
1740
1763
  return backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1741
1764
  }
1742
- function toError2(error) {
1743
- return error instanceof Error ? error : new Error(String(error));
1744
- }
1745
1765
  function sequential(tools) {
1746
1766
  return {
1747
1767
  name: `sequential(${tools.map((t) => t.name).join(" -> ")})`,
@@ -1806,42 +1826,23 @@ function retry(tool, options = {}) {
1806
1826
  return {
1807
1827
  name: `retry(${tool.name})`,
1808
1828
  description: `${tool.description} (with retry)`,
1809
- invoke: async (input) => {
1810
- let lastError = new Error(`Tool ${tool.name} failed without an explicit error`);
1811
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1812
- try {
1813
- return await tool.invoke(input);
1814
- } catch (error) {
1815
- lastError = toError2(error);
1816
- if (attempt < maxAttempts) {
1817
- const waitTime = calculateRetryDelay(attempt, delay, backoff);
1818
- await new Promise((resolve) => setTimeout(resolve, waitTime));
1819
- }
1820
- }
1821
- }
1822
- throw lastError;
1823
- }
1829
+ invoke: async (input) => executeWithRetries(
1830
+ () => tool.invoke(input),
1831
+ maxAttempts,
1832
+ (attempt) => calculateRetryDelay(attempt, delay, backoff),
1833
+ () => true
1834
+ )
1824
1835
  };
1825
1836
  }
1826
1837
  function timeout(tool, ms) {
1827
1838
  return {
1828
1839
  name: `timeout(${tool.name})`,
1829
1840
  description: `${tool.description} (with ${ms}ms timeout)`,
1830
- invoke: async (input) => {
1831
- let timer;
1832
- const timeoutPromise = new Promise((_, reject) => {
1833
- timer = setTimeout(() => {
1834
- reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`));
1835
- }, ms);
1836
- });
1837
- try {
1838
- return await Promise.race([tool.invoke(input), timeoutPromise]);
1839
- } finally {
1840
- if (timer !== void 0) {
1841
- clearTimeout(timer);
1842
- }
1843
- }
1844
- }
1841
+ invoke: async (input) => executeWithTimeout(
1842
+ () => tool.invoke(input),
1843
+ ms,
1844
+ () => new Error(`Tool ${tool.name} timed out after ${ms}ms`)
1845
+ )
1845
1846
  };
1846
1847
  }
1847
1848
  function cache(tool, ttl) {
@@ -2129,12 +2130,11 @@ function mergeState(currentState, update, config) {
2129
2130
  }
2130
2131
 
2131
2132
  // src/langgraph/builders/sequential.ts
2133
+ var import_langgraph3 = require("@langchain/langgraph");
2134
+
2135
+ // src/langgraph/builders/workflow-node-registration.ts
2132
2136
  var import_langgraph2 = require("@langchain/langgraph");
2133
- function createSequentialWorkflow(stateSchema, nodes, options = {}) {
2134
- const { autoStartEnd = true } = options;
2135
- if (nodes.length === 0) {
2136
- throw new Error("Sequential workflow must have at least one node");
2137
- }
2137
+ function createRegisteredWorkflowGraph(stateSchema, nodes, options = {}) {
2138
2138
  const nodeNames = /* @__PURE__ */ new Set();
2139
2139
  for (const node of nodes) {
2140
2140
  if (nodeNames.has(node.name)) {
@@ -2144,25 +2144,38 @@ function createSequentialWorkflow(stateSchema, nodes, options = {}) {
2144
2144
  }
2145
2145
  let graph;
2146
2146
  try {
2147
- graph = new import_langgraph2.StateGraph(
2148
- stateSchema
2149
- );
2147
+ graph = new import_langgraph2.StateGraph(stateSchema);
2150
2148
  } catch (error) {
2151
- throw new Error("Sequential workflow requires a LangGraph Annotation.Root schema", {
2152
- cause: error
2153
- });
2149
+ if (options.translateGraphConstructionError) {
2150
+ throw options.translateGraphConstructionError(error);
2151
+ }
2152
+ throw error;
2154
2153
  }
2155
- for (const { name: nodeName, node } of nodes) {
2156
- graph.addNode(nodeName, node);
2154
+ for (const { name, node } of nodes) {
2155
+ graph.addNode(name, node);
2157
2156
  }
2157
+ return graph;
2158
+ }
2159
+
2160
+ // src/langgraph/builders/sequential.ts
2161
+ function createSequentialWorkflow(stateSchema, nodes, options = {}) {
2162
+ const { autoStartEnd = true } = options;
2163
+ if (nodes.length === 0) {
2164
+ throw new Error("Sequential workflow must have at least one node");
2165
+ }
2166
+ const graph = createRegisteredWorkflowGraph(stateSchema, nodes, {
2167
+ translateGraphConstructionError: (error) => new Error("Sequential workflow requires a LangGraph Annotation.Root schema", {
2168
+ cause: error
2169
+ })
2170
+ });
2158
2171
  if (autoStartEnd) {
2159
- graph.addEdge(import_langgraph2.START, nodes[0].name);
2172
+ graph.addEdge(import_langgraph3.START, nodes[0].name);
2160
2173
  }
2161
2174
  for (let i = 0; i < nodes.length - 1; i++) {
2162
2175
  graph.addEdge(nodes[i].name, nodes[i + 1].name);
2163
2176
  }
2164
2177
  if (autoStartEnd) {
2165
- graph.addEdge(nodes[nodes.length - 1].name, import_langgraph2.END);
2178
+ graph.addEdge(nodes[nodes.length - 1].name, import_langgraph3.END);
2166
2179
  }
2167
2180
  return graph;
2168
2181
  }
@@ -2194,33 +2207,20 @@ function sequentialBuilder(stateSchema) {
2194
2207
  }
2195
2208
 
2196
2209
  // src/langgraph/builders/parallel.ts
2197
- var import_langgraph3 = require("@langchain/langgraph");
2210
+ var import_langgraph4 = require("@langchain/langgraph");
2198
2211
  function createParallelWorkflow(stateSchema, config, options = {}) {
2199
2212
  const { parallel: parallel2, aggregate } = config;
2200
2213
  const { autoStartEnd = true } = options;
2201
2214
  if (parallel2.length === 0) {
2202
2215
  throw new Error("Parallel workflow must have at least one parallel node");
2203
2216
  }
2204
- const nodeNames = /* @__PURE__ */ new Set();
2205
- for (const node of parallel2) {
2206
- if (nodeNames.has(node.name)) {
2207
- throw new Error(`Duplicate node name: ${node.name}`);
2208
- }
2209
- nodeNames.add(node.name);
2210
- }
2211
- if (aggregate && nodeNames.has(aggregate.name)) {
2212
- throw new Error(`Duplicate node name: ${aggregate.name}`);
2213
- }
2214
- const graph = new import_langgraph3.StateGraph(stateSchema);
2215
- for (const { name: nodeName, node } of parallel2) {
2216
- graph.addNode(nodeName, node);
2217
- }
2218
- if (aggregate) {
2219
- graph.addNode(aggregate.name, aggregate.node);
2220
- }
2217
+ const graph = createRegisteredWorkflowGraph(
2218
+ stateSchema,
2219
+ aggregate ? [...parallel2, aggregate] : parallel2
2220
+ );
2221
2221
  if (autoStartEnd) {
2222
2222
  for (const { name: nodeName } of parallel2) {
2223
- graph.addEdge(import_langgraph3.START, nodeName);
2223
+ graph.addEdge(import_langgraph4.START, nodeName);
2224
2224
  }
2225
2225
  }
2226
2226
  if (aggregate) {
@@ -2228,11 +2228,11 @@ function createParallelWorkflow(stateSchema, config, options = {}) {
2228
2228
  graph.addEdge(nodeName, aggregate.name);
2229
2229
  }
2230
2230
  if (autoStartEnd) {
2231
- graph.addEdge(aggregate.name, import_langgraph3.END);
2231
+ graph.addEdge(aggregate.name, import_langgraph4.END);
2232
2232
  }
2233
2233
  } else if (autoStartEnd) {
2234
2234
  for (const { name: nodeName } of parallel2) {
2235
- graph.addEdge(nodeName, import_langgraph3.END);
2235
+ graph.addEdge(nodeName, import_langgraph4.END);
2236
2236
  }
2237
2237
  }
2238
2238
  return graph;
@@ -2283,9 +2283,9 @@ function createMultiRouter(config) {
2283
2283
  }
2284
2284
 
2285
2285
  // src/langgraph/builders/subgraph.ts
2286
- var import_langgraph4 = require("@langchain/langgraph");
2286
+ var import_langgraph5 = require("@langchain/langgraph");
2287
2287
  function createSubgraph(stateSchema, builder) {
2288
- const graph = new import_langgraph4.StateGraph(stateSchema);
2288
+ const graph = new import_langgraph5.StateGraph(stateSchema);
2289
2289
  const configured = builder(graph);
2290
2290
  return configured.compile();
2291
2291
  }
@@ -3360,9 +3360,9 @@ function createSharedConcurrencyController(options = {}) {
3360
3360
  }
3361
3361
 
3362
3362
  // src/langgraph/persistence/checkpointer.ts
3363
- var import_langgraph5 = require("@langchain/langgraph");
3363
+ var import_langgraph6 = require("@langchain/langgraph");
3364
3364
  function createMemoryCheckpointer(options) {
3365
- return new import_langgraph5.MemorySaver();
3365
+ return new import_langgraph6.MemorySaver();
3366
3366
  }
3367
3367
  async function createSqliteCheckpointer(options = {}) {
3368
3368
  const { path = ":memory:", autoMigrate = true } = options;
@@ -3383,7 +3383,7 @@ async function createSqliteCheckpointer(options = {}) {
3383
3383
  }
3384
3384
  }
3385
3385
  function isMemoryCheckpointer(checkpointer) {
3386
- return checkpointer instanceof import_langgraph5.MemorySaver;
3386
+ return checkpointer instanceof import_langgraph6.MemorySaver;
3387
3387
  }
3388
3388
 
3389
3389
  // src/langgraph/persistence/thread.ts
@@ -4448,7 +4448,7 @@ function toErrorPayload(error) {
4448
4448
  }
4449
4449
  return { error: String(error) };
4450
4450
  }
4451
- function toError3(error) {
4451
+ function toError2(error) {
4452
4452
  if (error instanceof Error) {
4453
4453
  return error;
4454
4454
  }
@@ -4483,7 +4483,7 @@ var ConnectionPool = class {
4483
4483
  const interval = healthCheck.interval || 3e4;
4484
4484
  this.runtime.healthCheckTimer = setInterval(() => {
4485
4485
  performHealthChecks(this.runtime).catch((error) => {
4486
- const normalizedError = toError3(error);
4486
+ const normalizedError = toError2(error);
4487
4487
  logger4.error("Health check failed", toErrorPayload(normalizedError));
4488
4488
  options.onHealthCheckFail?.(normalizedError);
4489
4489
  });
package/dist/index.js CHANGED
@@ -1069,6 +1069,47 @@ function snapshotExecutionMetrics(metrics) {
1069
1069
  };
1070
1070
  }
1071
1071
 
1072
+ // src/tools/execution-resilience.ts
1073
+ function normalizeThrownValue(error) {
1074
+ return error instanceof Error ? error : new Error(String(error));
1075
+ }
1076
+ async function executeWithRetries(execute, maxAttempts, retryDelay, shouldRetry) {
1077
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1078
+ try {
1079
+ return await execute();
1080
+ } catch (thrownValue) {
1081
+ const error = normalizeThrownValue(thrownValue);
1082
+ if (attempt === maxAttempts || !shouldRetry(error)) {
1083
+ throw error;
1084
+ }
1085
+ await new Promise((resolve) => setTimeout(resolve, retryDelay(attempt, error)));
1086
+ }
1087
+ }
1088
+ throw new Error("Retry execution requires at least one attempt");
1089
+ }
1090
+ async function executeWithTimeout(execute, timeoutMs, timeoutError, startOrder = "timeout-first") {
1091
+ let timeoutId;
1092
+ const startTimeout = () => new Promise((_, reject) => {
1093
+ timeoutId = setTimeout(() => reject(timeoutError()), timeoutMs);
1094
+ });
1095
+ try {
1096
+ let executionPromise;
1097
+ let timeoutPromise;
1098
+ if (startOrder === "execution-first") {
1099
+ executionPromise = execute();
1100
+ timeoutPromise = startTimeout();
1101
+ } else {
1102
+ timeoutPromise = startTimeout();
1103
+ executionPromise = execute();
1104
+ }
1105
+ return await Promise.race([executionPromise, timeoutPromise]);
1106
+ } finally {
1107
+ if (timeoutId !== void 0) {
1108
+ clearTimeout(timeoutId);
1109
+ }
1110
+ }
1111
+ }
1112
+
1072
1113
  // src/tools/executor-retry.ts
1073
1114
  function calculateBackoff(attempt, policy) {
1074
1115
  const initialDelay = policy.initialDelay || 1e3;
@@ -1088,10 +1129,7 @@ function calculateBackoff(attempt, policy) {
1088
1129
  return Math.min(delay, maxDelay);
1089
1130
  }
1090
1131
  function toError(error) {
1091
- if (error instanceof Error) {
1092
- return error;
1093
- }
1094
- return new Error(String(error));
1132
+ return normalizeThrownValue(error);
1095
1133
  }
1096
1134
  function resolveExecutionMethod(tool, logger6) {
1097
1135
  const executeFn = tool.invoke || tool.execute;
@@ -1117,28 +1155,20 @@ async function executeWithRetry(tool, input, policy, logger6) {
1117
1155
  `Invalid retry policy: maxAttempts must be an integer >= 1 (received ${String(policy.maxAttempts)})`
1118
1156
  );
1119
1157
  }
1120
- let lastError;
1121
- for (let attempt = 1; attempt <= policy.maxAttempts; attempt++) {
1122
- try {
1123
- return await executeFn.call(tool, input);
1124
- } catch (error) {
1125
- const currentError = toError(error);
1126
- lastError = currentError;
1127
- if (policy.retryableErrors && policy.retryableErrors.length > 0) {
1128
- const isRetryable = policy.retryableErrors.some(
1129
- (message) => currentError.message.includes(message)
1130
- );
1131
- if (!isRetryable) {
1132
- throw currentError;
1133
- }
1134
- }
1135
- if (attempt < policy.maxAttempts) {
1136
- const delay = calculateBackoff(attempt, policy);
1137
- await new Promise((resolve) => setTimeout(resolve, delay));
1138
- }
1139
- }
1140
- }
1141
- throw lastError ?? new Error("Tool execution failed after retries");
1158
+ return executeWithRetries(
1159
+ () => executeFn.call(tool, input),
1160
+ policy.maxAttempts,
1161
+ (attempt) => calculateBackoff(attempt, policy),
1162
+ (error) => !policy.retryableErrors?.length || policy.retryableErrors.some((message) => error.message.includes(message))
1163
+ );
1164
+ }
1165
+ async function executeWithTimeout2(execute, timeout2) {
1166
+ return executeWithTimeout(
1167
+ execute,
1168
+ timeout2,
1169
+ () => new Error("Tool execution timeout"),
1170
+ "execution-first"
1171
+ );
1142
1172
  }
1143
1173
 
1144
1174
  // src/tools/executor-types.ts
@@ -1166,15 +1196,12 @@ function createToolExecutor(config = {}) {
1166
1196
  const metrics = createExecutionMetrics();
1167
1197
  async function executeSingle(tool, input, priority) {
1168
1198
  const startTime = Date.now();
1169
- let timeoutId;
1170
1199
  try {
1171
1200
  onExecutionStart?.(tool, input);
1172
- const result = await Promise.race([
1173
- executeWithRetry(tool, input, retryPolicy, logger2),
1174
- new Promise((_, reject) => {
1175
- timeoutId = setTimeout(() => reject(new Error("Tool execution timeout")), timeout2);
1176
- })
1177
- ]);
1201
+ const result = await executeWithTimeout2(
1202
+ () => executeWithRetry(tool, input, retryPolicy, logger2),
1203
+ timeout2
1204
+ );
1178
1205
  const duration = Date.now() - startTime;
1179
1206
  recordExecutionResult(metrics, priority, duration, true);
1180
1207
  onExecutionComplete?.(tool, input, result, duration);
@@ -1185,10 +1212,6 @@ function createToolExecutor(config = {}) {
1185
1212
  recordExecutionResult(metrics, priority, duration, false);
1186
1213
  onExecutionError?.(tool, input, normalizedError, duration);
1187
1214
  throw normalizedError;
1188
- } finally {
1189
- if (timeoutId) {
1190
- clearTimeout(timeoutId);
1191
- }
1192
1215
  }
1193
1216
  }
1194
1217
  function processQueue() {
@@ -1563,9 +1586,6 @@ function isConditionalStep(step) {
1563
1586
  function calculateRetryDelay(attempt, delay, backoff) {
1564
1587
  return backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1565
1588
  }
1566
- function toError2(error) {
1567
- return error instanceof Error ? error : new Error(String(error));
1568
- }
1569
1589
  function sequential(tools) {
1570
1590
  return {
1571
1591
  name: `sequential(${tools.map((t) => t.name).join(" -> ")})`,
@@ -1630,42 +1650,23 @@ function retry(tool, options = {}) {
1630
1650
  return {
1631
1651
  name: `retry(${tool.name})`,
1632
1652
  description: `${tool.description} (with retry)`,
1633
- invoke: async (input) => {
1634
- let lastError = new Error(`Tool ${tool.name} failed without an explicit error`);
1635
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1636
- try {
1637
- return await tool.invoke(input);
1638
- } catch (error) {
1639
- lastError = toError2(error);
1640
- if (attempt < maxAttempts) {
1641
- const waitTime = calculateRetryDelay(attempt, delay, backoff);
1642
- await new Promise((resolve) => setTimeout(resolve, waitTime));
1643
- }
1644
- }
1645
- }
1646
- throw lastError;
1647
- }
1653
+ invoke: async (input) => executeWithRetries(
1654
+ () => tool.invoke(input),
1655
+ maxAttempts,
1656
+ (attempt) => calculateRetryDelay(attempt, delay, backoff),
1657
+ () => true
1658
+ )
1648
1659
  };
1649
1660
  }
1650
1661
  function timeout(tool, ms) {
1651
1662
  return {
1652
1663
  name: `timeout(${tool.name})`,
1653
1664
  description: `${tool.description} (with ${ms}ms timeout)`,
1654
- invoke: async (input) => {
1655
- let timer;
1656
- const timeoutPromise = new Promise((_, reject) => {
1657
- timer = setTimeout(() => {
1658
- reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`));
1659
- }, ms);
1660
- });
1661
- try {
1662
- return await Promise.race([tool.invoke(input), timeoutPromise]);
1663
- } finally {
1664
- if (timer !== void 0) {
1665
- clearTimeout(timer);
1666
- }
1667
- }
1668
- }
1665
+ invoke: async (input) => executeWithTimeout(
1666
+ () => tool.invoke(input),
1667
+ ms,
1668
+ () => new Error(`Tool ${tool.name} timed out after ${ms}ms`)
1669
+ )
1669
1670
  };
1670
1671
  }
1671
1672
  function cache(tool, ttl) {
@@ -1953,12 +1954,11 @@ function mergeState(currentState, update, config) {
1953
1954
  }
1954
1955
 
1955
1956
  // src/langgraph/builders/sequential.ts
1956
- import { StateGraph, END, START } from "@langchain/langgraph";
1957
- function createSequentialWorkflow(stateSchema, nodes, options = {}) {
1958
- const { autoStartEnd = true } = options;
1959
- if (nodes.length === 0) {
1960
- throw new Error("Sequential workflow must have at least one node");
1961
- }
1957
+ import { END, START } from "@langchain/langgraph";
1958
+
1959
+ // src/langgraph/builders/workflow-node-registration.ts
1960
+ import { StateGraph } from "@langchain/langgraph";
1961
+ function createRegisteredWorkflowGraph(stateSchema, nodes, options = {}) {
1962
1962
  const nodeNames = /* @__PURE__ */ new Set();
1963
1963
  for (const node of nodes) {
1964
1964
  if (nodeNames.has(node.name)) {
@@ -1968,17 +1968,30 @@ function createSequentialWorkflow(stateSchema, nodes, options = {}) {
1968
1968
  }
1969
1969
  let graph;
1970
1970
  try {
1971
- graph = new StateGraph(
1972
- stateSchema
1973
- );
1971
+ graph = new StateGraph(stateSchema);
1974
1972
  } catch (error) {
1975
- throw new Error("Sequential workflow requires a LangGraph Annotation.Root schema", {
1976
- cause: error
1977
- });
1973
+ if (options.translateGraphConstructionError) {
1974
+ throw options.translateGraphConstructionError(error);
1975
+ }
1976
+ throw error;
1978
1977
  }
1979
- for (const { name: nodeName, node } of nodes) {
1980
- graph.addNode(nodeName, node);
1978
+ for (const { name, node } of nodes) {
1979
+ graph.addNode(name, node);
1981
1980
  }
1981
+ return graph;
1982
+ }
1983
+
1984
+ // src/langgraph/builders/sequential.ts
1985
+ function createSequentialWorkflow(stateSchema, nodes, options = {}) {
1986
+ const { autoStartEnd = true } = options;
1987
+ if (nodes.length === 0) {
1988
+ throw new Error("Sequential workflow must have at least one node");
1989
+ }
1990
+ const graph = createRegisteredWorkflowGraph(stateSchema, nodes, {
1991
+ translateGraphConstructionError: (error) => new Error("Sequential workflow requires a LangGraph Annotation.Root schema", {
1992
+ cause: error
1993
+ })
1994
+ });
1982
1995
  if (autoStartEnd) {
1983
1996
  graph.addEdge(START, nodes[0].name);
1984
1997
  }
@@ -2018,30 +2031,17 @@ function sequentialBuilder(stateSchema) {
2018
2031
  }
2019
2032
 
2020
2033
  // src/langgraph/builders/parallel.ts
2021
- import { StateGraph as StateGraph2, END as END2, START as START2 } from "@langchain/langgraph";
2034
+ import { END as END2, START as START2 } from "@langchain/langgraph";
2022
2035
  function createParallelWorkflow(stateSchema, config, options = {}) {
2023
2036
  const { parallel: parallel2, aggregate } = config;
2024
2037
  const { autoStartEnd = true } = options;
2025
2038
  if (parallel2.length === 0) {
2026
2039
  throw new Error("Parallel workflow must have at least one parallel node");
2027
2040
  }
2028
- const nodeNames = /* @__PURE__ */ new Set();
2029
- for (const node of parallel2) {
2030
- if (nodeNames.has(node.name)) {
2031
- throw new Error(`Duplicate node name: ${node.name}`);
2032
- }
2033
- nodeNames.add(node.name);
2034
- }
2035
- if (aggregate && nodeNames.has(aggregate.name)) {
2036
- throw new Error(`Duplicate node name: ${aggregate.name}`);
2037
- }
2038
- const graph = new StateGraph2(stateSchema);
2039
- for (const { name: nodeName, node } of parallel2) {
2040
- graph.addNode(nodeName, node);
2041
- }
2042
- if (aggregate) {
2043
- graph.addNode(aggregate.name, aggregate.node);
2044
- }
2041
+ const graph = createRegisteredWorkflowGraph(
2042
+ stateSchema,
2043
+ aggregate ? [...parallel2, aggregate] : parallel2
2044
+ );
2045
2045
  if (autoStartEnd) {
2046
2046
  for (const { name: nodeName } of parallel2) {
2047
2047
  graph.addEdge(START2, nodeName);
@@ -2107,9 +2107,9 @@ function createMultiRouter(config) {
2107
2107
  }
2108
2108
 
2109
2109
  // src/langgraph/builders/subgraph.ts
2110
- import { StateGraph as StateGraph3 } from "@langchain/langgraph";
2110
+ import { StateGraph as StateGraph2 } from "@langchain/langgraph";
2111
2111
  function createSubgraph(stateSchema, builder) {
2112
- const graph = new StateGraph3(stateSchema);
2112
+ const graph = new StateGraph2(stateSchema);
2113
2113
  const configured = builder(graph);
2114
2114
  return configured.compile();
2115
2115
  }
@@ -4272,7 +4272,7 @@ function toErrorPayload(error) {
4272
4272
  }
4273
4273
  return { error: String(error) };
4274
4274
  }
4275
- function toError3(error) {
4275
+ function toError2(error) {
4276
4276
  if (error instanceof Error) {
4277
4277
  return error;
4278
4278
  }
@@ -4307,7 +4307,7 @@ var ConnectionPool = class {
4307
4307
  const interval = healthCheck.interval || 3e4;
4308
4308
  this.runtime.healthCheckTimer = setInterval(() => {
4309
4309
  performHealthChecks(this.runtime).catch((error) => {
4310
- const normalizedError = toError3(error);
4310
+ const normalizedError = toError2(error);
4311
4311
  logger4.error("Health check failed", toErrorPayload(normalizedError));
4312
4312
  options.onHealthCheckFail?.(normalizedError);
4313
4313
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.18.7",
3
+ "version": "0.18.9",
4
4
  "description": "Production-ready TypeScript agent framework built on LangGraph with orchestration, middleware, and typed abstractions.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",