@agentforge/core 0.16.18 → 0.16.19

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
@@ -1846,6 +1846,12 @@ var ManagedTool = class {
1846
1846
  failedExecutions: 0
1847
1847
  };
1848
1848
  _healthCheckTimer;
1849
+ _beforeExitHandler;
1850
+ _healthCheckInFlight = false;
1851
+ _cleaningUp = false;
1852
+ _cleanupPromise;
1853
+ _initializePromise;
1854
+ _lifecycleGeneration = 0;
1849
1855
  constructor(config) {
1850
1856
  this.name = config.name;
1851
1857
  this.description = config.description;
@@ -1856,17 +1862,7 @@ var ManagedTool = class {
1856
1862
  this.autoCleanup = config.autoCleanup ?? true;
1857
1863
  this.healthCheckInterval = config.healthCheckInterval;
1858
1864
  this._context = config.context;
1859
- if (this.autoCleanup) {
1860
- process.on("beforeExit", () => {
1861
- this.cleanup().catch(
1862
- (err) => logger3.error("Cleanup failed", {
1863
- toolName: this.name,
1864
- error: err instanceof Error ? err.message : String(err),
1865
- ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1866
- })
1867
- );
1868
- });
1869
- }
1865
+ this.ensureBeforeExitHandler();
1870
1866
  }
1871
1867
  /**
1872
1868
  * Get the tool context (e.g., connection pool, API client)
@@ -1890,28 +1886,26 @@ var ManagedTool = class {
1890
1886
  * Initialize the tool
1891
1887
  */
1892
1888
  async initialize() {
1893
- if (this._initialized) {
1889
+ if (this._initializePromise) {
1890
+ await this._initializePromise;
1894
1891
  return;
1895
1892
  }
1896
- if (this.initializeFn) {
1897
- await this.initializeFn();
1893
+ if (this._cleanupPromise) {
1894
+ await this._cleanupPromise;
1895
+ if (this._initializePromise) {
1896
+ await this._initializePromise;
1897
+ return;
1898
+ }
1898
1899
  }
1899
- this._initialized = true;
1900
- this._stats.initialized = true;
1901
- if (this.healthCheckInterval && this.healthCheckFn) {
1902
- this._healthCheckTimer = setInterval(async () => {
1903
- try {
1904
- const result = await this.healthCheckFn();
1905
- this._stats.lastHealthCheck = result;
1906
- this._stats.lastHealthCheckTime = Date.now();
1907
- } catch (error) {
1908
- this._stats.lastHealthCheck = {
1909
- healthy: false,
1910
- error: error.message
1911
- };
1912
- this._stats.lastHealthCheckTime = Date.now();
1913
- }
1914
- }, this.healthCheckInterval);
1900
+ if (this._initialized) {
1901
+ return;
1902
+ }
1903
+ const initializePromise = this.performInitialize();
1904
+ this._initializePromise = initializePromise;
1905
+ try {
1906
+ await initializePromise;
1907
+ } finally {
1908
+ this._initializePromise = void 0;
1915
1909
  }
1916
1910
  }
1917
1911
  /**
@@ -1938,24 +1932,55 @@ var ManagedTool = class {
1938
1932
  * Cleanup the tool
1939
1933
  */
1940
1934
  async cleanup() {
1941
- if (!this._initialized) {
1935
+ if (this._cleanupPromise) {
1936
+ await this._cleanupPromise;
1942
1937
  return;
1943
1938
  }
1939
+ if (this._initializePromise) {
1940
+ try {
1941
+ await this._initializePromise;
1942
+ } catch {
1943
+ }
1944
+ }
1945
+ const cleanupPromise = this.performCleanup();
1946
+ this._cleanupPromise = cleanupPromise;
1947
+ try {
1948
+ await cleanupPromise;
1949
+ } finally {
1950
+ this._cleanupPromise = void 0;
1951
+ }
1952
+ }
1953
+ async performCleanup() {
1954
+ this._cleaningUp = true;
1944
1955
  if (this._healthCheckTimer) {
1945
1956
  clearInterval(this._healthCheckTimer);
1946
1957
  this._healthCheckTimer = void 0;
1947
1958
  }
1948
- if (this.cleanupFn) {
1949
- await this.cleanupFn();
1959
+ if (this._beforeExitHandler) {
1960
+ process.off("beforeExit", this._beforeExitHandler);
1961
+ this._beforeExitHandler = void 0;
1962
+ }
1963
+ if (!this._initialized) {
1964
+ this._cleaningUp = false;
1965
+ return;
1950
1966
  }
1951
1967
  this._initialized = false;
1952
1968
  this._stats.initialized = false;
1969
+ if (this.cleanupFn) {
1970
+ try {
1971
+ await this.cleanupFn();
1972
+ } finally {
1973
+ this._cleaningUp = false;
1974
+ }
1975
+ return;
1976
+ }
1977
+ this._cleaningUp = false;
1953
1978
  }
1954
1979
  /**
1955
1980
  * Run health check
1956
1981
  */
1957
1982
  async healthCheck() {
1958
- if (!this._initialized) {
1983
+ if (!this._initialized || this._cleaningUp) {
1959
1984
  return {
1960
1985
  healthy: false,
1961
1986
  error: "Tool is not initialized"
@@ -1967,15 +1992,28 @@ var ManagedTool = class {
1967
1992
  metadata: { message: "No health check configured" }
1968
1993
  };
1969
1994
  }
1995
+ const lifecycleGeneration = this._lifecycleGeneration;
1970
1996
  try {
1971
1997
  const result = await this.healthCheckFn();
1998
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1999
+ return {
2000
+ healthy: false,
2001
+ error: "Tool is not initialized"
2002
+ };
2003
+ }
1972
2004
  this._stats.lastHealthCheck = result;
1973
2005
  this._stats.lastHealthCheckTime = Date.now();
1974
2006
  return result;
1975
2007
  } catch (error) {
2008
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
2009
+ return {
2010
+ healthy: false,
2011
+ error: "Tool is not initialized"
2012
+ };
2013
+ }
1976
2014
  const result = {
1977
2015
  healthy: false,
1978
- error: error.message
2016
+ error: getErrorMessage(error)
1979
2017
  };
1980
2018
  this._stats.lastHealthCheck = result;
1981
2019
  this._stats.lastHealthCheckTime = Date.now();
@@ -2009,10 +2047,68 @@ var ManagedTool = class {
2009
2047
  }
2010
2048
  };
2011
2049
  }
2050
+ async runPeriodicHealthCheck() {
2051
+ if (!this.healthCheckFn || this._healthCheckInFlight || !this._initialized || this._cleaningUp) {
2052
+ return;
2053
+ }
2054
+ this._healthCheckInFlight = true;
2055
+ const lifecycleGeneration = this._lifecycleGeneration;
2056
+ try {
2057
+ const result = await this.healthCheckFn();
2058
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
2059
+ return;
2060
+ }
2061
+ this._stats.lastHealthCheck = result;
2062
+ this._stats.lastHealthCheckTime = Date.now();
2063
+ } catch (error) {
2064
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
2065
+ return;
2066
+ }
2067
+ this._stats.lastHealthCheck = {
2068
+ healthy: false,
2069
+ error: getErrorMessage(error)
2070
+ };
2071
+ this._stats.lastHealthCheckTime = Date.now();
2072
+ } finally {
2073
+ this._healthCheckInFlight = false;
2074
+ }
2075
+ }
2076
+ async performInitialize() {
2077
+ this.ensureBeforeExitHandler();
2078
+ this._lifecycleGeneration++;
2079
+ if (this.initializeFn) {
2080
+ await this.initializeFn();
2081
+ }
2082
+ this._initialized = true;
2083
+ this._stats.initialized = true;
2084
+ if (this.healthCheckInterval && this.healthCheckFn) {
2085
+ this._healthCheckTimer = setInterval(() => {
2086
+ void this.runPeriodicHealthCheck();
2087
+ }, this.healthCheckInterval);
2088
+ }
2089
+ }
2090
+ ensureBeforeExitHandler() {
2091
+ if (!this.autoCleanup || this._beforeExitHandler) {
2092
+ return;
2093
+ }
2094
+ this._beforeExitHandler = () => {
2095
+ this.cleanup().catch(
2096
+ (err) => logger3.error("Cleanup failed", {
2097
+ toolName: this.name,
2098
+ error: getErrorMessage(err),
2099
+ ...err instanceof Error && err.stack ? { stack: err.stack } : {}
2100
+ })
2101
+ );
2102
+ };
2103
+ process.on("beforeExit", this._beforeExitHandler);
2104
+ }
2012
2105
  };
2013
2106
  function createManagedTool(config) {
2014
2107
  return new ManagedTool(config);
2015
2108
  }
2109
+ function getErrorMessage(error) {
2110
+ return error instanceof Error ? error.message : String(error);
2111
+ }
2016
2112
 
2017
2113
  // src/tools/composition.ts
2018
2114
  function isConditionalStep(step) {
package/dist/index.d.cts CHANGED
@@ -1570,26 +1570,38 @@ declare function createToolExecutor(config?: ToolExecutorConfig): {
1570
1570
  };
1571
1571
  };
1572
1572
 
1573
+ /**
1574
+ * Shared JSON-safe payload contracts for observability and monitoring paths.
1575
+ */
1576
+ type JsonPrimitive = string | number | boolean | null;
1577
+ type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
1578
+ interface JsonObject {
1579
+ [key: string]: JsonValue;
1580
+ }
1581
+
1573
1582
  /**
1574
1583
  * Tool Lifecycle Management - Manage tool initialization, cleanup, and resources
1575
1584
  * @module tools/lifecycle
1576
1585
  */
1586
+
1577
1587
  interface ToolHealthCheckResult {
1578
1588
  healthy: boolean;
1579
1589
  error?: string;
1580
- metadata?: Record<string, any>;
1590
+ metadata?: JsonObject;
1581
1591
  }
1582
- interface ManagedToolConfig<TContext = any, TInput = any, TOutput = any> {
1592
+ interface ManagedToolConfigBase<TContext, TInput, TOutput> {
1583
1593
  name: string;
1584
1594
  description: string;
1585
1595
  initialize?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
1586
1596
  execute: (this: ManagedTool<TContext, TInput, TOutput>, input: TInput) => Promise<TOutput>;
1587
1597
  cleanup?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
1588
1598
  healthCheck?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<ToolHealthCheckResult>;
1589
- context?: TContext;
1590
1599
  autoCleanup?: boolean;
1591
1600
  healthCheckInterval?: number;
1592
1601
  }
1602
+ interface ManagedToolConfig<TContext = undefined, TInput = unknown, TOutput = unknown> extends ManagedToolConfigBase<TContext, TInput, TOutput> {
1603
+ context?: TContext;
1604
+ }
1593
1605
  interface ManagedToolStats {
1594
1606
  initialized: boolean;
1595
1607
  totalExecutions: number;
@@ -1602,7 +1614,7 @@ interface ManagedToolStats {
1602
1614
  /**
1603
1615
  * Managed tool with lifecycle hooks
1604
1616
  */
1605
- declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1617
+ declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown> {
1606
1618
  readonly name: string;
1607
1619
  readonly description: string;
1608
1620
  private readonly initializeFn?;
@@ -1615,15 +1627,21 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1615
1627
  private _context;
1616
1628
  private _stats;
1617
1629
  private _healthCheckTimer?;
1630
+ private _beforeExitHandler?;
1631
+ private _healthCheckInFlight;
1632
+ private _cleaningUp;
1633
+ private _cleanupPromise?;
1634
+ private _initializePromise?;
1635
+ private _lifecycleGeneration;
1618
1636
  constructor(config: ManagedToolConfig<TContext, TInput, TOutput>);
1619
1637
  /**
1620
1638
  * Get the tool context (e.g., connection pool, API client)
1621
1639
  */
1622
- get context(): TContext;
1640
+ get context(): TContext | undefined;
1623
1641
  /**
1624
1642
  * Set the tool context
1625
1643
  */
1626
- set context(value: TContext);
1644
+ set context(value: TContext | undefined);
1627
1645
  /**
1628
1646
  * Check if tool is initialized
1629
1647
  */
@@ -1640,6 +1658,7 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1640
1658
  * Cleanup the tool
1641
1659
  */
1642
1660
  cleanup(): Promise<void>;
1661
+ private performCleanup;
1643
1662
  /**
1644
1663
  * Run health check
1645
1664
  */
@@ -1660,11 +1679,14 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1660
1679
  description: string;
1661
1680
  invoke: (input: TInput) => Promise<TOutput>;
1662
1681
  };
1682
+ private runPeriodicHealthCheck;
1683
+ private performInitialize;
1684
+ private ensureBeforeExitHandler;
1663
1685
  }
1664
1686
  /**
1665
1687
  * Create a managed tool
1666
1688
  */
1667
- declare function createManagedTool<TContext = any, TInput = any, TOutput = any>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
1689
+ declare function createManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
1668
1690
 
1669
1691
  /**
1670
1692
  * Tool Composition - Compose tools into higher-level operations
@@ -2815,15 +2837,6 @@ interface ErrorHandlerOptions<State> {
2815
2837
  */
2816
2838
  declare function withErrorHandler<State>(node: (state: State) => State | Promise<State> | Partial<State> | Promise<Partial<State>>, options: ErrorHandlerOptions<State>): (state: State) => Promise<State | Partial<State>>;
2817
2839
 
2818
- /**
2819
- * Shared JSON-safe payload contracts for observability and monitoring paths.
2820
- */
2821
- type JsonPrimitive = string | number | boolean | null;
2822
- type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
2823
- interface JsonObject {
2824
- [key: string]: JsonValue;
2825
- }
2826
-
2827
2840
  /**
2828
2841
  * Structured Logging Utilities
2829
2842
  *
package/dist/index.d.ts CHANGED
@@ -1570,26 +1570,38 @@ declare function createToolExecutor(config?: ToolExecutorConfig): {
1570
1570
  };
1571
1571
  };
1572
1572
 
1573
+ /**
1574
+ * Shared JSON-safe payload contracts for observability and monitoring paths.
1575
+ */
1576
+ type JsonPrimitive = string | number | boolean | null;
1577
+ type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
1578
+ interface JsonObject {
1579
+ [key: string]: JsonValue;
1580
+ }
1581
+
1573
1582
  /**
1574
1583
  * Tool Lifecycle Management - Manage tool initialization, cleanup, and resources
1575
1584
  * @module tools/lifecycle
1576
1585
  */
1586
+
1577
1587
  interface ToolHealthCheckResult {
1578
1588
  healthy: boolean;
1579
1589
  error?: string;
1580
- metadata?: Record<string, any>;
1590
+ metadata?: JsonObject;
1581
1591
  }
1582
- interface ManagedToolConfig<TContext = any, TInput = any, TOutput = any> {
1592
+ interface ManagedToolConfigBase<TContext, TInput, TOutput> {
1583
1593
  name: string;
1584
1594
  description: string;
1585
1595
  initialize?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
1586
1596
  execute: (this: ManagedTool<TContext, TInput, TOutput>, input: TInput) => Promise<TOutput>;
1587
1597
  cleanup?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
1588
1598
  healthCheck?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<ToolHealthCheckResult>;
1589
- context?: TContext;
1590
1599
  autoCleanup?: boolean;
1591
1600
  healthCheckInterval?: number;
1592
1601
  }
1602
+ interface ManagedToolConfig<TContext = undefined, TInput = unknown, TOutput = unknown> extends ManagedToolConfigBase<TContext, TInput, TOutput> {
1603
+ context?: TContext;
1604
+ }
1593
1605
  interface ManagedToolStats {
1594
1606
  initialized: boolean;
1595
1607
  totalExecutions: number;
@@ -1602,7 +1614,7 @@ interface ManagedToolStats {
1602
1614
  /**
1603
1615
  * Managed tool with lifecycle hooks
1604
1616
  */
1605
- declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1617
+ declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown> {
1606
1618
  readonly name: string;
1607
1619
  readonly description: string;
1608
1620
  private readonly initializeFn?;
@@ -1615,15 +1627,21 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1615
1627
  private _context;
1616
1628
  private _stats;
1617
1629
  private _healthCheckTimer?;
1630
+ private _beforeExitHandler?;
1631
+ private _healthCheckInFlight;
1632
+ private _cleaningUp;
1633
+ private _cleanupPromise?;
1634
+ private _initializePromise?;
1635
+ private _lifecycleGeneration;
1618
1636
  constructor(config: ManagedToolConfig<TContext, TInput, TOutput>);
1619
1637
  /**
1620
1638
  * Get the tool context (e.g., connection pool, API client)
1621
1639
  */
1622
- get context(): TContext;
1640
+ get context(): TContext | undefined;
1623
1641
  /**
1624
1642
  * Set the tool context
1625
1643
  */
1626
- set context(value: TContext);
1644
+ set context(value: TContext | undefined);
1627
1645
  /**
1628
1646
  * Check if tool is initialized
1629
1647
  */
@@ -1640,6 +1658,7 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1640
1658
  * Cleanup the tool
1641
1659
  */
1642
1660
  cleanup(): Promise<void>;
1661
+ private performCleanup;
1643
1662
  /**
1644
1663
  * Run health check
1645
1664
  */
@@ -1660,11 +1679,14 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
1660
1679
  description: string;
1661
1680
  invoke: (input: TInput) => Promise<TOutput>;
1662
1681
  };
1682
+ private runPeriodicHealthCheck;
1683
+ private performInitialize;
1684
+ private ensureBeforeExitHandler;
1663
1685
  }
1664
1686
  /**
1665
1687
  * Create a managed tool
1666
1688
  */
1667
- declare function createManagedTool<TContext = any, TInput = any, TOutput = any>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
1689
+ declare function createManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
1668
1690
 
1669
1691
  /**
1670
1692
  * Tool Composition - Compose tools into higher-level operations
@@ -2815,15 +2837,6 @@ interface ErrorHandlerOptions<State> {
2815
2837
  */
2816
2838
  declare function withErrorHandler<State>(node: (state: State) => State | Promise<State> | Partial<State> | Promise<Partial<State>>, options: ErrorHandlerOptions<State>): (state: State) => Promise<State | Partial<State>>;
2817
2839
 
2818
- /**
2819
- * Shared JSON-safe payload contracts for observability and monitoring paths.
2820
- */
2821
- type JsonPrimitive = string | number | boolean | null;
2822
- type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
2823
- interface JsonObject {
2824
- [key: string]: JsonValue;
2825
- }
2826
-
2827
2840
  /**
2828
2841
  * Structured Logging Utilities
2829
2842
  *
package/dist/index.js CHANGED
@@ -1671,6 +1671,12 @@ var ManagedTool = class {
1671
1671
  failedExecutions: 0
1672
1672
  };
1673
1673
  _healthCheckTimer;
1674
+ _beforeExitHandler;
1675
+ _healthCheckInFlight = false;
1676
+ _cleaningUp = false;
1677
+ _cleanupPromise;
1678
+ _initializePromise;
1679
+ _lifecycleGeneration = 0;
1674
1680
  constructor(config) {
1675
1681
  this.name = config.name;
1676
1682
  this.description = config.description;
@@ -1681,17 +1687,7 @@ var ManagedTool = class {
1681
1687
  this.autoCleanup = config.autoCleanup ?? true;
1682
1688
  this.healthCheckInterval = config.healthCheckInterval;
1683
1689
  this._context = config.context;
1684
- if (this.autoCleanup) {
1685
- process.on("beforeExit", () => {
1686
- this.cleanup().catch(
1687
- (err) => logger3.error("Cleanup failed", {
1688
- toolName: this.name,
1689
- error: err instanceof Error ? err.message : String(err),
1690
- ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1691
- })
1692
- );
1693
- });
1694
- }
1690
+ this.ensureBeforeExitHandler();
1695
1691
  }
1696
1692
  /**
1697
1693
  * Get the tool context (e.g., connection pool, API client)
@@ -1715,28 +1711,26 @@ var ManagedTool = class {
1715
1711
  * Initialize the tool
1716
1712
  */
1717
1713
  async initialize() {
1718
- if (this._initialized) {
1714
+ if (this._initializePromise) {
1715
+ await this._initializePromise;
1719
1716
  return;
1720
1717
  }
1721
- if (this.initializeFn) {
1722
- await this.initializeFn();
1718
+ if (this._cleanupPromise) {
1719
+ await this._cleanupPromise;
1720
+ if (this._initializePromise) {
1721
+ await this._initializePromise;
1722
+ return;
1723
+ }
1723
1724
  }
1724
- this._initialized = true;
1725
- this._stats.initialized = true;
1726
- if (this.healthCheckInterval && this.healthCheckFn) {
1727
- this._healthCheckTimer = setInterval(async () => {
1728
- try {
1729
- const result = await this.healthCheckFn();
1730
- this._stats.lastHealthCheck = result;
1731
- this._stats.lastHealthCheckTime = Date.now();
1732
- } catch (error) {
1733
- this._stats.lastHealthCheck = {
1734
- healthy: false,
1735
- error: error.message
1736
- };
1737
- this._stats.lastHealthCheckTime = Date.now();
1738
- }
1739
- }, this.healthCheckInterval);
1725
+ if (this._initialized) {
1726
+ return;
1727
+ }
1728
+ const initializePromise = this.performInitialize();
1729
+ this._initializePromise = initializePromise;
1730
+ try {
1731
+ await initializePromise;
1732
+ } finally {
1733
+ this._initializePromise = void 0;
1740
1734
  }
1741
1735
  }
1742
1736
  /**
@@ -1763,24 +1757,55 @@ var ManagedTool = class {
1763
1757
  * Cleanup the tool
1764
1758
  */
1765
1759
  async cleanup() {
1766
- if (!this._initialized) {
1760
+ if (this._cleanupPromise) {
1761
+ await this._cleanupPromise;
1767
1762
  return;
1768
1763
  }
1764
+ if (this._initializePromise) {
1765
+ try {
1766
+ await this._initializePromise;
1767
+ } catch {
1768
+ }
1769
+ }
1770
+ const cleanupPromise = this.performCleanup();
1771
+ this._cleanupPromise = cleanupPromise;
1772
+ try {
1773
+ await cleanupPromise;
1774
+ } finally {
1775
+ this._cleanupPromise = void 0;
1776
+ }
1777
+ }
1778
+ async performCleanup() {
1779
+ this._cleaningUp = true;
1769
1780
  if (this._healthCheckTimer) {
1770
1781
  clearInterval(this._healthCheckTimer);
1771
1782
  this._healthCheckTimer = void 0;
1772
1783
  }
1773
- if (this.cleanupFn) {
1774
- await this.cleanupFn();
1784
+ if (this._beforeExitHandler) {
1785
+ process.off("beforeExit", this._beforeExitHandler);
1786
+ this._beforeExitHandler = void 0;
1787
+ }
1788
+ if (!this._initialized) {
1789
+ this._cleaningUp = false;
1790
+ return;
1775
1791
  }
1776
1792
  this._initialized = false;
1777
1793
  this._stats.initialized = false;
1794
+ if (this.cleanupFn) {
1795
+ try {
1796
+ await this.cleanupFn();
1797
+ } finally {
1798
+ this._cleaningUp = false;
1799
+ }
1800
+ return;
1801
+ }
1802
+ this._cleaningUp = false;
1778
1803
  }
1779
1804
  /**
1780
1805
  * Run health check
1781
1806
  */
1782
1807
  async healthCheck() {
1783
- if (!this._initialized) {
1808
+ if (!this._initialized || this._cleaningUp) {
1784
1809
  return {
1785
1810
  healthy: false,
1786
1811
  error: "Tool is not initialized"
@@ -1792,15 +1817,28 @@ var ManagedTool = class {
1792
1817
  metadata: { message: "No health check configured" }
1793
1818
  };
1794
1819
  }
1820
+ const lifecycleGeneration = this._lifecycleGeneration;
1795
1821
  try {
1796
1822
  const result = await this.healthCheckFn();
1823
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1824
+ return {
1825
+ healthy: false,
1826
+ error: "Tool is not initialized"
1827
+ };
1828
+ }
1797
1829
  this._stats.lastHealthCheck = result;
1798
1830
  this._stats.lastHealthCheckTime = Date.now();
1799
1831
  return result;
1800
1832
  } catch (error) {
1833
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1834
+ return {
1835
+ healthy: false,
1836
+ error: "Tool is not initialized"
1837
+ };
1838
+ }
1801
1839
  const result = {
1802
1840
  healthy: false,
1803
- error: error.message
1841
+ error: getErrorMessage(error)
1804
1842
  };
1805
1843
  this._stats.lastHealthCheck = result;
1806
1844
  this._stats.lastHealthCheckTime = Date.now();
@@ -1834,10 +1872,68 @@ var ManagedTool = class {
1834
1872
  }
1835
1873
  };
1836
1874
  }
1875
+ async runPeriodicHealthCheck() {
1876
+ if (!this.healthCheckFn || this._healthCheckInFlight || !this._initialized || this._cleaningUp) {
1877
+ return;
1878
+ }
1879
+ this._healthCheckInFlight = true;
1880
+ const lifecycleGeneration = this._lifecycleGeneration;
1881
+ try {
1882
+ const result = await this.healthCheckFn();
1883
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1884
+ return;
1885
+ }
1886
+ this._stats.lastHealthCheck = result;
1887
+ this._stats.lastHealthCheckTime = Date.now();
1888
+ } catch (error) {
1889
+ if (!this._initialized || this._cleaningUp || this._lifecycleGeneration !== lifecycleGeneration) {
1890
+ return;
1891
+ }
1892
+ this._stats.lastHealthCheck = {
1893
+ healthy: false,
1894
+ error: getErrorMessage(error)
1895
+ };
1896
+ this._stats.lastHealthCheckTime = Date.now();
1897
+ } finally {
1898
+ this._healthCheckInFlight = false;
1899
+ }
1900
+ }
1901
+ async performInitialize() {
1902
+ this.ensureBeforeExitHandler();
1903
+ this._lifecycleGeneration++;
1904
+ if (this.initializeFn) {
1905
+ await this.initializeFn();
1906
+ }
1907
+ this._initialized = true;
1908
+ this._stats.initialized = true;
1909
+ if (this.healthCheckInterval && this.healthCheckFn) {
1910
+ this._healthCheckTimer = setInterval(() => {
1911
+ void this.runPeriodicHealthCheck();
1912
+ }, this.healthCheckInterval);
1913
+ }
1914
+ }
1915
+ ensureBeforeExitHandler() {
1916
+ if (!this.autoCleanup || this._beforeExitHandler) {
1917
+ return;
1918
+ }
1919
+ this._beforeExitHandler = () => {
1920
+ this.cleanup().catch(
1921
+ (err) => logger3.error("Cleanup failed", {
1922
+ toolName: this.name,
1923
+ error: getErrorMessage(err),
1924
+ ...err instanceof Error && err.stack ? { stack: err.stack } : {}
1925
+ })
1926
+ );
1927
+ };
1928
+ process.on("beforeExit", this._beforeExitHandler);
1929
+ }
1837
1930
  };
1838
1931
  function createManagedTool(config) {
1839
1932
  return new ManagedTool(config);
1840
1933
  }
1934
+ function getErrorMessage(error) {
1935
+ return error instanceof Error ? error.message : String(error);
1936
+ }
1841
1937
 
1842
1938
  // src/tools/composition.ts
1843
1939
  function isConditionalStep(step) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.16.18",
3
+ "version": "0.16.19",
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",