@agentforge/core 0.16.43 → 0.16.45

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.cjs CHANGED
@@ -1482,7 +1482,155 @@ function createToolExecutor(config = {}) {
1482
1482
  };
1483
1483
  }
1484
1484
 
1485
- // src/tools/lifecycle.ts
1485
+ // src/tools/lifecycle-error.ts
1486
+ function getErrorMessage(error) {
1487
+ return error instanceof Error ? error.message : String(error);
1488
+ }
1489
+
1490
+ // src/tools/lifecycle-health.ts
1491
+ function setHealthStats(state, result) {
1492
+ state.stats.lastHealthCheck = result;
1493
+ state.stats.lastHealthCheckTime = Date.now();
1494
+ }
1495
+ function isLifecycleStale(state, lifecycleGeneration) {
1496
+ return !state.initialized || state.cleaningUp || state.lifecycleGeneration !== lifecycleGeneration;
1497
+ }
1498
+ async function runManagedHealthCheck(state, healthCheckFn) {
1499
+ if (!state.initialized || state.cleaningUp) {
1500
+ return {
1501
+ healthy: false,
1502
+ error: "Tool is not initialized"
1503
+ };
1504
+ }
1505
+ if (!healthCheckFn) {
1506
+ return {
1507
+ healthy: true,
1508
+ metadata: { message: "No health check configured" }
1509
+ };
1510
+ }
1511
+ const lifecycleGeneration = state.lifecycleGeneration;
1512
+ try {
1513
+ const result = await healthCheckFn();
1514
+ if (isLifecycleStale(state, lifecycleGeneration)) {
1515
+ return {
1516
+ healthy: false,
1517
+ error: "Tool is not initialized"
1518
+ };
1519
+ }
1520
+ setHealthStats(state, result);
1521
+ return result;
1522
+ } catch (error) {
1523
+ if (isLifecycleStale(state, lifecycleGeneration)) {
1524
+ return {
1525
+ healthy: false,
1526
+ error: "Tool is not initialized"
1527
+ };
1528
+ }
1529
+ const result = {
1530
+ healthy: false,
1531
+ error: getErrorMessage(error)
1532
+ };
1533
+ setHealthStats(state, result);
1534
+ return result;
1535
+ }
1536
+ }
1537
+ async function runPeriodicManagedHealthCheck(state, healthCheckFn) {
1538
+ if (!healthCheckFn || state.healthCheckInFlight || !state.initialized || state.cleaningUp) {
1539
+ return;
1540
+ }
1541
+ state.healthCheckInFlight = true;
1542
+ const lifecycleGeneration = state.lifecycleGeneration;
1543
+ try {
1544
+ const result = await healthCheckFn();
1545
+ if (!isLifecycleStale(state, lifecycleGeneration)) {
1546
+ setHealthStats(state, result);
1547
+ }
1548
+ } catch (error) {
1549
+ if (!isLifecycleStale(state, lifecycleGeneration)) {
1550
+ setHealthStats(state, {
1551
+ healthy: false,
1552
+ error: getErrorMessage(error)
1553
+ });
1554
+ }
1555
+ } finally {
1556
+ state.healthCheckInFlight = false;
1557
+ }
1558
+ }
1559
+
1560
+ // src/tools/lifecycle-hooks.ts
1561
+ async function performManagedInitialize({
1562
+ ensureBeforeExitHandler,
1563
+ healthCheckFn,
1564
+ healthCheckInterval,
1565
+ initializeFn,
1566
+ runPeriodicHealthCheck,
1567
+ state
1568
+ }) {
1569
+ ensureBeforeExitHandler();
1570
+ state.lifecycleGeneration++;
1571
+ if (initializeFn) {
1572
+ await initializeFn();
1573
+ }
1574
+ state.initialized = true;
1575
+ state.stats.initialized = true;
1576
+ if (healthCheckInterval && healthCheckFn) {
1577
+ state.healthCheckTimer = setInterval(() => {
1578
+ void runPeriodicHealthCheck();
1579
+ }, healthCheckInterval);
1580
+ }
1581
+ }
1582
+ async function performManagedCleanup({
1583
+ cleanupFn,
1584
+ state
1585
+ }) {
1586
+ state.cleaningUp = true;
1587
+ if (state.healthCheckTimer) {
1588
+ clearInterval(state.healthCheckTimer);
1589
+ state.healthCheckTimer = void 0;
1590
+ }
1591
+ if (state.beforeExitHandler) {
1592
+ process.off("beforeExit", state.beforeExitHandler);
1593
+ state.beforeExitHandler = void 0;
1594
+ }
1595
+ if (!state.initialized) {
1596
+ state.cleaningUp = false;
1597
+ return;
1598
+ }
1599
+ state.initialized = false;
1600
+ state.stats.initialized = false;
1601
+ if (cleanupFn) {
1602
+ try {
1603
+ await cleanupFn();
1604
+ } finally {
1605
+ state.cleaningUp = false;
1606
+ }
1607
+ return;
1608
+ }
1609
+ state.cleaningUp = false;
1610
+ }
1611
+ function ensureManagedBeforeExitHandler({
1612
+ autoCleanup,
1613
+ cleanup,
1614
+ logger: logger6,
1615
+ name,
1616
+ state
1617
+ }) {
1618
+ if (!autoCleanup || state.beforeExitHandler) {
1619
+ return;
1620
+ }
1621
+ state.beforeExitHandler = () => {
1622
+ cleanup().catch(
1623
+ (err) => logger6.error("Cleanup failed", {
1624
+ toolName: name,
1625
+ error: getErrorMessage(err),
1626
+ ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1627
+ })
1628
+ );
1629
+ };
1630
+ process.on("beforeExit", state.beforeExitHandler);
1631
+ }
1632
+
1633
+ // src/tools/lifecycle-managed-tool.ts
1486
1634
  var logger3 = createLogger("agentforge:core:tools:lifecycle", { level: "info" /* INFO */ });
1487
1635
  var ManagedTool = class {
1488
1636
  name;
@@ -1493,21 +1641,7 @@ var ManagedTool = class {
1493
1641
  healthCheckFn;
1494
1642
  autoCleanup;
1495
1643
  healthCheckInterval;
1496
- _initialized = false;
1497
- _context;
1498
- _stats = {
1499
- initialized: false,
1500
- totalExecutions: 0,
1501
- successfulExecutions: 0,
1502
- failedExecutions: 0
1503
- };
1504
- _healthCheckTimer;
1505
- _beforeExitHandler;
1506
- _healthCheckInFlight = false;
1507
- _cleaningUp = false;
1508
- _cleanupPromise;
1509
- _initializePromise;
1510
- _lifecycleGeneration = 0;
1644
+ state;
1511
1645
  constructor(config) {
1512
1646
  this.name = config.name;
1513
1647
  this.description = config.description;
@@ -1517,254 +1651,134 @@ var ManagedTool = class {
1517
1651
  this.healthCheckFn = config.healthCheck?.bind(this);
1518
1652
  this.autoCleanup = config.autoCleanup ?? true;
1519
1653
  this.healthCheckInterval = config.healthCheckInterval;
1520
- this._context = config.context;
1654
+ this.state = {
1655
+ initialized: false,
1656
+ context: config.context,
1657
+ stats: {
1658
+ initialized: false,
1659
+ totalExecutions: 0,
1660
+ successfulExecutions: 0,
1661
+ failedExecutions: 0
1662
+ },
1663
+ healthCheckInFlight: false,
1664
+ cleaningUp: false,
1665
+ lifecycleGeneration: 0
1666
+ };
1521
1667
  this.ensureBeforeExitHandler();
1522
1668
  }
1523
- /**
1524
- * Get the tool context (e.g., connection pool, API client)
1525
- */
1526
1669
  get context() {
1527
- return this._context;
1670
+ return this.state.context;
1528
1671
  }
1529
- /**
1530
- * Set the tool context
1531
- */
1532
1672
  set context(value) {
1533
- this._context = value;
1673
+ this.state.context = value;
1534
1674
  }
1535
- /**
1536
- * Check if tool is initialized
1537
- */
1538
1675
  get initialized() {
1539
- return this._initialized;
1676
+ return this.state.initialized;
1540
1677
  }
1541
- /**
1542
- * Initialize the tool
1543
- */
1544
1678
  async initialize() {
1545
- if (this._initializePromise) {
1546
- await this._initializePromise;
1679
+ if (this.state.initializePromise) {
1680
+ await this.state.initializePromise;
1547
1681
  return;
1548
1682
  }
1549
- if (this._cleanupPromise) {
1550
- await this._cleanupPromise;
1551
- if (this._initializePromise) {
1552
- await this._initializePromise;
1683
+ if (this.state.cleanupPromise) {
1684
+ await this.state.cleanupPromise;
1685
+ if (this.state.initializePromise) {
1686
+ await this.state.initializePromise;
1553
1687
  return;
1554
1688
  }
1555
1689
  }
1556
- if (this._initialized) {
1690
+ if (this.state.initialized) {
1557
1691
  return;
1558
1692
  }
1559
- const initializePromise = this.performInitialize();
1560
- this._initializePromise = initializePromise;
1693
+ const initializePromise = performManagedInitialize({
1694
+ ensureBeforeExitHandler: () => this.ensureBeforeExitHandler(),
1695
+ healthCheckFn: this.healthCheckFn,
1696
+ healthCheckInterval: this.healthCheckInterval,
1697
+ initializeFn: this.initializeFn,
1698
+ runPeriodicHealthCheck: () => this.runPeriodicHealthCheck(),
1699
+ state: this.state
1700
+ });
1701
+ this.state.initializePromise = initializePromise;
1561
1702
  try {
1562
1703
  await initializePromise;
1563
1704
  } finally {
1564
- this._initializePromise = void 0;
1705
+ this.state.initializePromise = void 0;
1565
1706
  }
1566
1707
  }
1567
- /**
1568
- * Execute the tool
1569
- */
1570
1708
  async execute(input) {
1571
- if (!this._initialized) {
1709
+ if (!this.state.initialized) {
1572
1710
  throw new Error(`Tool ${this.name} is not initialized. Call initialize() first.`);
1573
1711
  }
1574
1712
  const startTime = Date.now();
1575
- this._stats.totalExecutions++;
1713
+ this.state.stats.totalExecutions++;
1576
1714
  try {
1577
1715
  const result = await this.executeFn(input);
1578
- this._stats.successfulExecutions++;
1579
- this._stats.lastExecutionTime = Date.now() - startTime;
1716
+ this.state.stats.successfulExecutions++;
1717
+ this.state.stats.lastExecutionTime = Date.now() - startTime;
1580
1718
  return result;
1581
1719
  } catch (error) {
1582
- this._stats.failedExecutions++;
1583
- this._stats.lastExecutionTime = Date.now() - startTime;
1720
+ this.state.stats.failedExecutions++;
1721
+ this.state.stats.lastExecutionTime = Date.now() - startTime;
1584
1722
  throw error;
1585
1723
  }
1586
1724
  }
1587
- /**
1588
- * Cleanup the tool
1589
- */
1590
1725
  async cleanup() {
1591
- if (this._cleanupPromise) {
1592
- await this._cleanupPromise;
1726
+ if (this.state.cleanupPromise) {
1727
+ await this.state.cleanupPromise;
1593
1728
  return;
1594
1729
  }
1595
- if (this._initializePromise) {
1730
+ if (this.state.initializePromise) {
1596
1731
  try {
1597
- await this._initializePromise;
1732
+ await this.state.initializePromise;
1598
1733
  } catch {
1599
1734
  }
1600
1735
  }
1601
- const cleanupPromise = this.performCleanup();
1602
- this._cleanupPromise = cleanupPromise;
1736
+ const cleanupPromise = performManagedCleanup({
1737
+ cleanupFn: this.cleanupFn,
1738
+ state: this.state
1739
+ });
1740
+ this.state.cleanupPromise = cleanupPromise;
1603
1741
  try {
1604
1742
  await cleanupPromise;
1605
1743
  } finally {
1606
- this._cleanupPromise = void 0;
1607
- }
1608
- }
1609
- async performCleanup() {
1610
- this._cleaningUp = true;
1611
- if (this._healthCheckTimer) {
1612
- clearInterval(this._healthCheckTimer);
1613
- this._healthCheckTimer = void 0;
1614
- }
1615
- if (this._beforeExitHandler) {
1616
- process.off("beforeExit", this._beforeExitHandler);
1617
- this._beforeExitHandler = void 0;
1618
- }
1619
- if (!this._initialized) {
1620
- this._cleaningUp = false;
1621
- return;
1744
+ this.state.cleanupPromise = void 0;
1622
1745
  }
1623
- this._initialized = false;
1624
- this._stats.initialized = false;
1625
- if (this.cleanupFn) {
1626
- try {
1627
- await this.cleanupFn();
1628
- } finally {
1629
- this._cleaningUp = false;
1630
- }
1631
- return;
1632
- }
1633
- this._cleaningUp = false;
1634
1746
  }
1635
- /**
1636
- * Run health check
1637
- */
1638
1747
  async healthCheck() {
1639
- if (!this._initialized || this._cleaningUp) {
1640
- return {
1641
- healthy: false,
1642
- error: "Tool is not initialized"
1643
- };
1644
- }
1645
- if (!this.healthCheckFn) {
1646
- return {
1647
- healthy: true,
1648
- metadata: { message: "No health check configured" }
1649
- };
1650
- }
1651
- const lifecycleGeneration = this._lifecycleGeneration;
1652
- try {
1653
- const result = await this.healthCheckFn();
1654
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1655
- return {
1656
- healthy: false,
1657
- error: "Tool is not initialized"
1658
- };
1659
- }
1660
- this._stats.lastHealthCheck = result;
1661
- this._stats.lastHealthCheckTime = Date.now();
1662
- return result;
1663
- } catch (error) {
1664
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1665
- return {
1666
- healthy: false,
1667
- error: "Tool is not initialized"
1668
- };
1669
- }
1670
- const result = {
1671
- healthy: false,
1672
- error: getErrorMessage(error)
1673
- };
1674
- this._stats.lastHealthCheck = result;
1675
- this._stats.lastHealthCheckTime = Date.now();
1676
- return result;
1677
- }
1748
+ return runManagedHealthCheck(this.state, this.healthCheckFn);
1678
1749
  }
1679
- /**
1680
- * Get tool statistics
1681
- */
1682
1750
  getStats() {
1683
- return { ...this._stats };
1751
+ return { ...this.state.stats };
1684
1752
  }
1685
- /**
1686
- * Reset statistics
1687
- */
1688
1753
  resetStats() {
1689
- this._stats.totalExecutions = 0;
1690
- this._stats.successfulExecutions = 0;
1691
- this._stats.failedExecutions = 0;
1692
- this._stats.lastExecutionTime = void 0;
1754
+ this.state.stats.totalExecutions = 0;
1755
+ this.state.stats.successfulExecutions = 0;
1756
+ this.state.stats.failedExecutions = 0;
1757
+ this.state.stats.lastExecutionTime = void 0;
1693
1758
  }
1694
- /**
1695
- * Convert to LangChain tool format
1696
- */
1697
1759
  toLangChainTool() {
1698
1760
  return {
1699
1761
  name: this.name,
1700
1762
  description: this.description,
1701
- invoke: async (input) => {
1702
- return await this.execute(input);
1703
- }
1763
+ invoke: async (input) => this.execute(input)
1704
1764
  };
1705
1765
  }
1706
1766
  async runPeriodicHealthCheck() {
1707
- if (!this.healthCheckFn || this._healthCheckInFlight || !this._initialized || this._cleaningUp) {
1708
- return;
1709
- }
1710
- this._healthCheckInFlight = true;
1711
- const lifecycleGeneration = this._lifecycleGeneration;
1712
- try {
1713
- const result = await this.healthCheckFn();
1714
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1715
- return;
1716
- }
1717
- this._stats.lastHealthCheck = result;
1718
- this._stats.lastHealthCheckTime = Date.now();
1719
- } catch (error) {
1720
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1721
- return;
1722
- }
1723
- this._stats.lastHealthCheck = {
1724
- healthy: false,
1725
- error: getErrorMessage(error)
1726
- };
1727
- this._stats.lastHealthCheckTime = Date.now();
1728
- } finally {
1729
- this._healthCheckInFlight = false;
1730
- }
1731
- }
1732
- async performInitialize() {
1733
- this.ensureBeforeExitHandler();
1734
- this._lifecycleGeneration++;
1735
- if (this.initializeFn) {
1736
- await this.initializeFn();
1737
- }
1738
- this._initialized = true;
1739
- this._stats.initialized = true;
1740
- if (this.healthCheckInterval && this.healthCheckFn) {
1741
- this._healthCheckTimer = setInterval(() => {
1742
- void this.runPeriodicHealthCheck();
1743
- }, this.healthCheckInterval);
1744
- }
1767
+ await runPeriodicManagedHealthCheck(this.state, this.healthCheckFn);
1745
1768
  }
1746
1769
  ensureBeforeExitHandler() {
1747
- if (!this.autoCleanup || this._beforeExitHandler) {
1748
- return;
1749
- }
1750
- this._beforeExitHandler = () => {
1751
- this.cleanup().catch(
1752
- (err) => logger3.error("Cleanup failed", {
1753
- toolName: this.name,
1754
- error: getErrorMessage(err),
1755
- ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1756
- })
1757
- );
1758
- };
1759
- process.on("beforeExit", this._beforeExitHandler);
1770
+ ensureManagedBeforeExitHandler({
1771
+ autoCleanup: this.autoCleanup,
1772
+ cleanup: () => this.cleanup(),
1773
+ logger: logger3,
1774
+ name: this.name,
1775
+ state: this.state
1776
+ });
1760
1777
  }
1761
1778
  };
1762
1779
  function createManagedTool(config) {
1763
1780
  return new ManagedTool(config);
1764
1781
  }
1765
- function getErrorMessage(error) {
1766
- return error instanceof Error ? error.message : String(error);
1767
- }
1768
1782
 
1769
1783
  // src/tools/composition.ts
1770
1784
  function isConditionalStep(step) {
package/dist/index.d.cts CHANGED
@@ -1077,11 +1077,6 @@ interface JsonObject {
1077
1077
  [key: string]: JsonValue;
1078
1078
  }
1079
1079
 
1080
- /**
1081
- * Tool Lifecycle Management - Manage tool initialization, cleanup, and resources
1082
- * @module tools/lifecycle
1083
- */
1084
-
1085
1080
  interface ToolHealthCheckResult {
1086
1081
  healthy: boolean;
1087
1082
  error?: string;
@@ -1109,9 +1104,7 @@ interface ManagedToolStats {
1109
1104
  lastHealthCheck?: ToolHealthCheckResult;
1110
1105
  lastHealthCheckTime?: number;
1111
1106
  }
1112
- /**
1113
- * Managed tool with lifecycle hooks
1114
- */
1107
+
1115
1108
  declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown> {
1116
1109
  readonly name: string;
1117
1110
  readonly description: string;
@@ -1121,69 +1114,25 @@ declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unkn
1121
1114
  private readonly healthCheckFn?;
1122
1115
  private readonly autoCleanup;
1123
1116
  private readonly healthCheckInterval?;
1124
- private _initialized;
1125
- private _context;
1126
- private _stats;
1127
- private _healthCheckTimer?;
1128
- private _beforeExitHandler?;
1129
- private _healthCheckInFlight;
1130
- private _cleaningUp;
1131
- private _cleanupPromise?;
1132
- private _initializePromise?;
1133
- private _lifecycleGeneration;
1117
+ private readonly state;
1134
1118
  constructor(config: ManagedToolConfig<TContext, TInput, TOutput>);
1135
- /**
1136
- * Get the tool context (e.g., connection pool, API client)
1137
- */
1138
1119
  get context(): TContext | undefined;
1139
- /**
1140
- * Set the tool context
1141
- */
1142
1120
  set context(value: TContext | undefined);
1143
- /**
1144
- * Check if tool is initialized
1145
- */
1146
1121
  get initialized(): boolean;
1147
- /**
1148
- * Initialize the tool
1149
- */
1150
1122
  initialize(): Promise<void>;
1151
- /**
1152
- * Execute the tool
1153
- */
1154
1123
  execute(input: TInput): Promise<TOutput>;
1155
- /**
1156
- * Cleanup the tool
1157
- */
1158
1124
  cleanup(): Promise<void>;
1159
- private performCleanup;
1160
- /**
1161
- * Run health check
1162
- */
1163
1125
  healthCheck(): Promise<ToolHealthCheckResult>;
1164
- /**
1165
- * Get tool statistics
1166
- */
1167
1126
  getStats(): ManagedToolStats;
1168
- /**
1169
- * Reset statistics
1170
- */
1171
1127
  resetStats(): void;
1172
- /**
1173
- * Convert to LangChain tool format
1174
- */
1175
1128
  toLangChainTool(): {
1176
1129
  name: string;
1177
1130
  description: string;
1178
1131
  invoke: (input: TInput) => Promise<TOutput>;
1179
1132
  };
1180
1133
  private runPeriodicHealthCheck;
1181
- private performInitialize;
1182
1134
  private ensureBeforeExitHandler;
1183
1135
  }
1184
- /**
1185
- * Create a managed tool
1186
- */
1187
1136
  declare function createManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
1188
1137
 
1189
1138
  /**
package/dist/index.d.ts CHANGED
@@ -1077,11 +1077,6 @@ interface JsonObject {
1077
1077
  [key: string]: JsonValue;
1078
1078
  }
1079
1079
 
1080
- /**
1081
- * Tool Lifecycle Management - Manage tool initialization, cleanup, and resources
1082
- * @module tools/lifecycle
1083
- */
1084
-
1085
1080
  interface ToolHealthCheckResult {
1086
1081
  healthy: boolean;
1087
1082
  error?: string;
@@ -1109,9 +1104,7 @@ interface ManagedToolStats {
1109
1104
  lastHealthCheck?: ToolHealthCheckResult;
1110
1105
  lastHealthCheckTime?: number;
1111
1106
  }
1112
- /**
1113
- * Managed tool with lifecycle hooks
1114
- */
1107
+
1115
1108
  declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown> {
1116
1109
  readonly name: string;
1117
1110
  readonly description: string;
@@ -1121,69 +1114,25 @@ declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unkn
1121
1114
  private readonly healthCheckFn?;
1122
1115
  private readonly autoCleanup;
1123
1116
  private readonly healthCheckInterval?;
1124
- private _initialized;
1125
- private _context;
1126
- private _stats;
1127
- private _healthCheckTimer?;
1128
- private _beforeExitHandler?;
1129
- private _healthCheckInFlight;
1130
- private _cleaningUp;
1131
- private _cleanupPromise?;
1132
- private _initializePromise?;
1133
- private _lifecycleGeneration;
1117
+ private readonly state;
1134
1118
  constructor(config: ManagedToolConfig<TContext, TInput, TOutput>);
1135
- /**
1136
- * Get the tool context (e.g., connection pool, API client)
1137
- */
1138
1119
  get context(): TContext | undefined;
1139
- /**
1140
- * Set the tool context
1141
- */
1142
1120
  set context(value: TContext | undefined);
1143
- /**
1144
- * Check if tool is initialized
1145
- */
1146
1121
  get initialized(): boolean;
1147
- /**
1148
- * Initialize the tool
1149
- */
1150
1122
  initialize(): Promise<void>;
1151
- /**
1152
- * Execute the tool
1153
- */
1154
1123
  execute(input: TInput): Promise<TOutput>;
1155
- /**
1156
- * Cleanup the tool
1157
- */
1158
1124
  cleanup(): Promise<void>;
1159
- private performCleanup;
1160
- /**
1161
- * Run health check
1162
- */
1163
1125
  healthCheck(): Promise<ToolHealthCheckResult>;
1164
- /**
1165
- * Get tool statistics
1166
- */
1167
1126
  getStats(): ManagedToolStats;
1168
- /**
1169
- * Reset statistics
1170
- */
1171
1127
  resetStats(): void;
1172
- /**
1173
- * Convert to LangChain tool format
1174
- */
1175
1128
  toLangChainTool(): {
1176
1129
  name: string;
1177
1130
  description: string;
1178
1131
  invoke: (input: TInput) => Promise<TOutput>;
1179
1132
  };
1180
1133
  private runPeriodicHealthCheck;
1181
- private performInitialize;
1182
1134
  private ensureBeforeExitHandler;
1183
1135
  }
1184
- /**
1185
- * Create a managed tool
1186
- */
1187
1136
  declare function createManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
1188
1137
 
1189
1138
  /**
package/dist/index.js CHANGED
@@ -1307,7 +1307,155 @@ function createToolExecutor(config = {}) {
1307
1307
  };
1308
1308
  }
1309
1309
 
1310
- // src/tools/lifecycle.ts
1310
+ // src/tools/lifecycle-error.ts
1311
+ function getErrorMessage(error) {
1312
+ return error instanceof Error ? error.message : String(error);
1313
+ }
1314
+
1315
+ // src/tools/lifecycle-health.ts
1316
+ function setHealthStats(state, result) {
1317
+ state.stats.lastHealthCheck = result;
1318
+ state.stats.lastHealthCheckTime = Date.now();
1319
+ }
1320
+ function isLifecycleStale(state, lifecycleGeneration) {
1321
+ return !state.initialized || state.cleaningUp || state.lifecycleGeneration !== lifecycleGeneration;
1322
+ }
1323
+ async function runManagedHealthCheck(state, healthCheckFn) {
1324
+ if (!state.initialized || state.cleaningUp) {
1325
+ return {
1326
+ healthy: false,
1327
+ error: "Tool is not initialized"
1328
+ };
1329
+ }
1330
+ if (!healthCheckFn) {
1331
+ return {
1332
+ healthy: true,
1333
+ metadata: { message: "No health check configured" }
1334
+ };
1335
+ }
1336
+ const lifecycleGeneration = state.lifecycleGeneration;
1337
+ try {
1338
+ const result = await healthCheckFn();
1339
+ if (isLifecycleStale(state, lifecycleGeneration)) {
1340
+ return {
1341
+ healthy: false,
1342
+ error: "Tool is not initialized"
1343
+ };
1344
+ }
1345
+ setHealthStats(state, result);
1346
+ return result;
1347
+ } catch (error) {
1348
+ if (isLifecycleStale(state, lifecycleGeneration)) {
1349
+ return {
1350
+ healthy: false,
1351
+ error: "Tool is not initialized"
1352
+ };
1353
+ }
1354
+ const result = {
1355
+ healthy: false,
1356
+ error: getErrorMessage(error)
1357
+ };
1358
+ setHealthStats(state, result);
1359
+ return result;
1360
+ }
1361
+ }
1362
+ async function runPeriodicManagedHealthCheck(state, healthCheckFn) {
1363
+ if (!healthCheckFn || state.healthCheckInFlight || !state.initialized || state.cleaningUp) {
1364
+ return;
1365
+ }
1366
+ state.healthCheckInFlight = true;
1367
+ const lifecycleGeneration = state.lifecycleGeneration;
1368
+ try {
1369
+ const result = await healthCheckFn();
1370
+ if (!isLifecycleStale(state, lifecycleGeneration)) {
1371
+ setHealthStats(state, result);
1372
+ }
1373
+ } catch (error) {
1374
+ if (!isLifecycleStale(state, lifecycleGeneration)) {
1375
+ setHealthStats(state, {
1376
+ healthy: false,
1377
+ error: getErrorMessage(error)
1378
+ });
1379
+ }
1380
+ } finally {
1381
+ state.healthCheckInFlight = false;
1382
+ }
1383
+ }
1384
+
1385
+ // src/tools/lifecycle-hooks.ts
1386
+ async function performManagedInitialize({
1387
+ ensureBeforeExitHandler,
1388
+ healthCheckFn,
1389
+ healthCheckInterval,
1390
+ initializeFn,
1391
+ runPeriodicHealthCheck,
1392
+ state
1393
+ }) {
1394
+ ensureBeforeExitHandler();
1395
+ state.lifecycleGeneration++;
1396
+ if (initializeFn) {
1397
+ await initializeFn();
1398
+ }
1399
+ state.initialized = true;
1400
+ state.stats.initialized = true;
1401
+ if (healthCheckInterval && healthCheckFn) {
1402
+ state.healthCheckTimer = setInterval(() => {
1403
+ void runPeriodicHealthCheck();
1404
+ }, healthCheckInterval);
1405
+ }
1406
+ }
1407
+ async function performManagedCleanup({
1408
+ cleanupFn,
1409
+ state
1410
+ }) {
1411
+ state.cleaningUp = true;
1412
+ if (state.healthCheckTimer) {
1413
+ clearInterval(state.healthCheckTimer);
1414
+ state.healthCheckTimer = void 0;
1415
+ }
1416
+ if (state.beforeExitHandler) {
1417
+ process.off("beforeExit", state.beforeExitHandler);
1418
+ state.beforeExitHandler = void 0;
1419
+ }
1420
+ if (!state.initialized) {
1421
+ state.cleaningUp = false;
1422
+ return;
1423
+ }
1424
+ state.initialized = false;
1425
+ state.stats.initialized = false;
1426
+ if (cleanupFn) {
1427
+ try {
1428
+ await cleanupFn();
1429
+ } finally {
1430
+ state.cleaningUp = false;
1431
+ }
1432
+ return;
1433
+ }
1434
+ state.cleaningUp = false;
1435
+ }
1436
+ function ensureManagedBeforeExitHandler({
1437
+ autoCleanup,
1438
+ cleanup,
1439
+ logger: logger6,
1440
+ name,
1441
+ state
1442
+ }) {
1443
+ if (!autoCleanup || state.beforeExitHandler) {
1444
+ return;
1445
+ }
1446
+ state.beforeExitHandler = () => {
1447
+ cleanup().catch(
1448
+ (err) => logger6.error("Cleanup failed", {
1449
+ toolName: name,
1450
+ error: getErrorMessage(err),
1451
+ ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1452
+ })
1453
+ );
1454
+ };
1455
+ process.on("beforeExit", state.beforeExitHandler);
1456
+ }
1457
+
1458
+ // src/tools/lifecycle-managed-tool.ts
1311
1459
  var logger3 = createLogger("agentforge:core:tools:lifecycle", { level: "info" /* INFO */ });
1312
1460
  var ManagedTool = class {
1313
1461
  name;
@@ -1318,21 +1466,7 @@ var ManagedTool = class {
1318
1466
  healthCheckFn;
1319
1467
  autoCleanup;
1320
1468
  healthCheckInterval;
1321
- _initialized = false;
1322
- _context;
1323
- _stats = {
1324
- initialized: false,
1325
- totalExecutions: 0,
1326
- successfulExecutions: 0,
1327
- failedExecutions: 0
1328
- };
1329
- _healthCheckTimer;
1330
- _beforeExitHandler;
1331
- _healthCheckInFlight = false;
1332
- _cleaningUp = false;
1333
- _cleanupPromise;
1334
- _initializePromise;
1335
- _lifecycleGeneration = 0;
1469
+ state;
1336
1470
  constructor(config) {
1337
1471
  this.name = config.name;
1338
1472
  this.description = config.description;
@@ -1342,254 +1476,134 @@ var ManagedTool = class {
1342
1476
  this.healthCheckFn = config.healthCheck?.bind(this);
1343
1477
  this.autoCleanup = config.autoCleanup ?? true;
1344
1478
  this.healthCheckInterval = config.healthCheckInterval;
1345
- this._context = config.context;
1479
+ this.state = {
1480
+ initialized: false,
1481
+ context: config.context,
1482
+ stats: {
1483
+ initialized: false,
1484
+ totalExecutions: 0,
1485
+ successfulExecutions: 0,
1486
+ failedExecutions: 0
1487
+ },
1488
+ healthCheckInFlight: false,
1489
+ cleaningUp: false,
1490
+ lifecycleGeneration: 0
1491
+ };
1346
1492
  this.ensureBeforeExitHandler();
1347
1493
  }
1348
- /**
1349
- * Get the tool context (e.g., connection pool, API client)
1350
- */
1351
1494
  get context() {
1352
- return this._context;
1495
+ return this.state.context;
1353
1496
  }
1354
- /**
1355
- * Set the tool context
1356
- */
1357
1497
  set context(value) {
1358
- this._context = value;
1498
+ this.state.context = value;
1359
1499
  }
1360
- /**
1361
- * Check if tool is initialized
1362
- */
1363
1500
  get initialized() {
1364
- return this._initialized;
1501
+ return this.state.initialized;
1365
1502
  }
1366
- /**
1367
- * Initialize the tool
1368
- */
1369
1503
  async initialize() {
1370
- if (this._initializePromise) {
1371
- await this._initializePromise;
1504
+ if (this.state.initializePromise) {
1505
+ await this.state.initializePromise;
1372
1506
  return;
1373
1507
  }
1374
- if (this._cleanupPromise) {
1375
- await this._cleanupPromise;
1376
- if (this._initializePromise) {
1377
- await this._initializePromise;
1508
+ if (this.state.cleanupPromise) {
1509
+ await this.state.cleanupPromise;
1510
+ if (this.state.initializePromise) {
1511
+ await this.state.initializePromise;
1378
1512
  return;
1379
1513
  }
1380
1514
  }
1381
- if (this._initialized) {
1515
+ if (this.state.initialized) {
1382
1516
  return;
1383
1517
  }
1384
- const initializePromise = this.performInitialize();
1385
- this._initializePromise = initializePromise;
1518
+ const initializePromise = performManagedInitialize({
1519
+ ensureBeforeExitHandler: () => this.ensureBeforeExitHandler(),
1520
+ healthCheckFn: this.healthCheckFn,
1521
+ healthCheckInterval: this.healthCheckInterval,
1522
+ initializeFn: this.initializeFn,
1523
+ runPeriodicHealthCheck: () => this.runPeriodicHealthCheck(),
1524
+ state: this.state
1525
+ });
1526
+ this.state.initializePromise = initializePromise;
1386
1527
  try {
1387
1528
  await initializePromise;
1388
1529
  } finally {
1389
- this._initializePromise = void 0;
1530
+ this.state.initializePromise = void 0;
1390
1531
  }
1391
1532
  }
1392
- /**
1393
- * Execute the tool
1394
- */
1395
1533
  async execute(input) {
1396
- if (!this._initialized) {
1534
+ if (!this.state.initialized) {
1397
1535
  throw new Error(`Tool ${this.name} is not initialized. Call initialize() first.`);
1398
1536
  }
1399
1537
  const startTime = Date.now();
1400
- this._stats.totalExecutions++;
1538
+ this.state.stats.totalExecutions++;
1401
1539
  try {
1402
1540
  const result = await this.executeFn(input);
1403
- this._stats.successfulExecutions++;
1404
- this._stats.lastExecutionTime = Date.now() - startTime;
1541
+ this.state.stats.successfulExecutions++;
1542
+ this.state.stats.lastExecutionTime = Date.now() - startTime;
1405
1543
  return result;
1406
1544
  } catch (error) {
1407
- this._stats.failedExecutions++;
1408
- this._stats.lastExecutionTime = Date.now() - startTime;
1545
+ this.state.stats.failedExecutions++;
1546
+ this.state.stats.lastExecutionTime = Date.now() - startTime;
1409
1547
  throw error;
1410
1548
  }
1411
1549
  }
1412
- /**
1413
- * Cleanup the tool
1414
- */
1415
1550
  async cleanup() {
1416
- if (this._cleanupPromise) {
1417
- await this._cleanupPromise;
1551
+ if (this.state.cleanupPromise) {
1552
+ await this.state.cleanupPromise;
1418
1553
  return;
1419
1554
  }
1420
- if (this._initializePromise) {
1555
+ if (this.state.initializePromise) {
1421
1556
  try {
1422
- await this._initializePromise;
1557
+ await this.state.initializePromise;
1423
1558
  } catch {
1424
1559
  }
1425
1560
  }
1426
- const cleanupPromise = this.performCleanup();
1427
- this._cleanupPromise = cleanupPromise;
1561
+ const cleanupPromise = performManagedCleanup({
1562
+ cleanupFn: this.cleanupFn,
1563
+ state: this.state
1564
+ });
1565
+ this.state.cleanupPromise = cleanupPromise;
1428
1566
  try {
1429
1567
  await cleanupPromise;
1430
1568
  } finally {
1431
- this._cleanupPromise = void 0;
1432
- }
1433
- }
1434
- async performCleanup() {
1435
- this._cleaningUp = true;
1436
- if (this._healthCheckTimer) {
1437
- clearInterval(this._healthCheckTimer);
1438
- this._healthCheckTimer = void 0;
1439
- }
1440
- if (this._beforeExitHandler) {
1441
- process.off("beforeExit", this._beforeExitHandler);
1442
- this._beforeExitHandler = void 0;
1443
- }
1444
- if (!this._initialized) {
1445
- this._cleaningUp = false;
1446
- return;
1569
+ this.state.cleanupPromise = void 0;
1447
1570
  }
1448
- this._initialized = false;
1449
- this._stats.initialized = false;
1450
- if (this.cleanupFn) {
1451
- try {
1452
- await this.cleanupFn();
1453
- } finally {
1454
- this._cleaningUp = false;
1455
- }
1456
- return;
1457
- }
1458
- this._cleaningUp = false;
1459
1571
  }
1460
- /**
1461
- * Run health check
1462
- */
1463
1572
  async healthCheck() {
1464
- if (!this._initialized || this._cleaningUp) {
1465
- return {
1466
- healthy: false,
1467
- error: "Tool is not initialized"
1468
- };
1469
- }
1470
- if (!this.healthCheckFn) {
1471
- return {
1472
- healthy: true,
1473
- metadata: { message: "No health check configured" }
1474
- };
1475
- }
1476
- const lifecycleGeneration = this._lifecycleGeneration;
1477
- try {
1478
- const result = await this.healthCheckFn();
1479
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1480
- return {
1481
- healthy: false,
1482
- error: "Tool is not initialized"
1483
- };
1484
- }
1485
- this._stats.lastHealthCheck = result;
1486
- this._stats.lastHealthCheckTime = Date.now();
1487
- return result;
1488
- } catch (error) {
1489
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1490
- return {
1491
- healthy: false,
1492
- error: "Tool is not initialized"
1493
- };
1494
- }
1495
- const result = {
1496
- healthy: false,
1497
- error: getErrorMessage(error)
1498
- };
1499
- this._stats.lastHealthCheck = result;
1500
- this._stats.lastHealthCheckTime = Date.now();
1501
- return result;
1502
- }
1573
+ return runManagedHealthCheck(this.state, this.healthCheckFn);
1503
1574
  }
1504
- /**
1505
- * Get tool statistics
1506
- */
1507
1575
  getStats() {
1508
- return { ...this._stats };
1576
+ return { ...this.state.stats };
1509
1577
  }
1510
- /**
1511
- * Reset statistics
1512
- */
1513
1578
  resetStats() {
1514
- this._stats.totalExecutions = 0;
1515
- this._stats.successfulExecutions = 0;
1516
- this._stats.failedExecutions = 0;
1517
- this._stats.lastExecutionTime = void 0;
1579
+ this.state.stats.totalExecutions = 0;
1580
+ this.state.stats.successfulExecutions = 0;
1581
+ this.state.stats.failedExecutions = 0;
1582
+ this.state.stats.lastExecutionTime = void 0;
1518
1583
  }
1519
- /**
1520
- * Convert to LangChain tool format
1521
- */
1522
1584
  toLangChainTool() {
1523
1585
  return {
1524
1586
  name: this.name,
1525
1587
  description: this.description,
1526
- invoke: async (input) => {
1527
- return await this.execute(input);
1528
- }
1588
+ invoke: async (input) => this.execute(input)
1529
1589
  };
1530
1590
  }
1531
1591
  async runPeriodicHealthCheck() {
1532
- if (!this.healthCheckFn || this._healthCheckInFlight || !this._initialized || this._cleaningUp) {
1533
- return;
1534
- }
1535
- this._healthCheckInFlight = true;
1536
- const lifecycleGeneration = this._lifecycleGeneration;
1537
- try {
1538
- const result = await this.healthCheckFn();
1539
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1540
- return;
1541
- }
1542
- this._stats.lastHealthCheck = result;
1543
- this._stats.lastHealthCheckTime = Date.now();
1544
- } catch (error) {
1545
- if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1546
- return;
1547
- }
1548
- this._stats.lastHealthCheck = {
1549
- healthy: false,
1550
- error: getErrorMessage(error)
1551
- };
1552
- this._stats.lastHealthCheckTime = Date.now();
1553
- } finally {
1554
- this._healthCheckInFlight = false;
1555
- }
1556
- }
1557
- async performInitialize() {
1558
- this.ensureBeforeExitHandler();
1559
- this._lifecycleGeneration++;
1560
- if (this.initializeFn) {
1561
- await this.initializeFn();
1562
- }
1563
- this._initialized = true;
1564
- this._stats.initialized = true;
1565
- if (this.healthCheckInterval && this.healthCheckFn) {
1566
- this._healthCheckTimer = setInterval(() => {
1567
- void this.runPeriodicHealthCheck();
1568
- }, this.healthCheckInterval);
1569
- }
1592
+ await runPeriodicManagedHealthCheck(this.state, this.healthCheckFn);
1570
1593
  }
1571
1594
  ensureBeforeExitHandler() {
1572
- if (!this.autoCleanup || this._beforeExitHandler) {
1573
- return;
1574
- }
1575
- this._beforeExitHandler = () => {
1576
- this.cleanup().catch(
1577
- (err) => logger3.error("Cleanup failed", {
1578
- toolName: this.name,
1579
- error: getErrorMessage(err),
1580
- ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1581
- })
1582
- );
1583
- };
1584
- process.on("beforeExit", this._beforeExitHandler);
1595
+ ensureManagedBeforeExitHandler({
1596
+ autoCleanup: this.autoCleanup,
1597
+ cleanup: () => this.cleanup(),
1598
+ logger: logger3,
1599
+ name: this.name,
1600
+ state: this.state
1601
+ });
1585
1602
  }
1586
1603
  };
1587
1604
  function createManagedTool(config) {
1588
1605
  return new ManagedTool(config);
1589
1606
  }
1590
- function getErrorMessage(error) {
1591
- return error instanceof Error ? error.message : String(error);
1592
- }
1593
1607
 
1594
1608
  // src/tools/composition.ts
1595
1609
  function isConditionalStep(step) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.16.43",
3
+ "version": "0.16.45",
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",