@agentforge/core 0.15.4 → 0.15.6

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
@@ -1566,7 +1566,7 @@ function createToolExecutor(config = {}) {
1566
1566
  }
1567
1567
  return Math.min(delay, maxDelay);
1568
1568
  }
1569
- function toError(error) {
1569
+ function toError2(error) {
1570
1570
  if (error instanceof Error) {
1571
1571
  return error;
1572
1572
  }
@@ -1597,7 +1597,7 @@ function createToolExecutor(config = {}) {
1597
1597
  try {
1598
1598
  return await executeFn.call(tool, input);
1599
1599
  } catch (error) {
1600
- const currentError = toError(error);
1600
+ const currentError = toError2(error);
1601
1601
  lastError = currentError;
1602
1602
  if (policy.retryableErrors && policy.retryableErrors.length > 0) {
1603
1603
  const isRetryable = policy.retryableErrors.some(
@@ -1635,7 +1635,7 @@ function createToolExecutor(config = {}) {
1635
1635
  return result;
1636
1636
  } catch (error) {
1637
1637
  const duration = Date.now() - startTime;
1638
- const normalizedError = toError(error);
1638
+ const normalizedError = toError2(error);
1639
1639
  metrics.totalExecutions++;
1640
1640
  metrics.failedExecutions++;
1641
1641
  metrics.totalDuration += duration;
@@ -1902,6 +1902,15 @@ function createManagedTool(config) {
1902
1902
  }
1903
1903
 
1904
1904
  // src/tools/composition.ts
1905
+ function isConditionalStep(step) {
1906
+ return !Array.isArray(step) && "condition" in step;
1907
+ }
1908
+ function calculateRetryDelay(attempt, delay, backoff) {
1909
+ return backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1910
+ }
1911
+ function toError(error) {
1912
+ return error instanceof Error ? error : new Error(String(error));
1913
+ }
1905
1914
  function sequential(tools) {
1906
1915
  return {
1907
1916
  name: `sequential(${tools.map((t) => t.name).join(" -> ")})`,
@@ -1945,7 +1954,7 @@ function composeTool(config) {
1945
1954
  for (const step of config.steps) {
1946
1955
  if (Array.isArray(step)) {
1947
1956
  result = await parallel(step).invoke(result);
1948
- } else if ("condition" in step) {
1957
+ } else if (isConditionalStep(step)) {
1949
1958
  result = await conditional(step).invoke(result);
1950
1959
  } else {
1951
1960
  result = await step.invoke(result);
@@ -1960,18 +1969,21 @@ function composeTool(config) {
1960
1969
  }
1961
1970
  function retry(tool, options = {}) {
1962
1971
  const { maxAttempts = 3, delay = 1e3, backoff = "exponential" } = options;
1972
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
1973
+ throw new Error("Invalid retry options: maxAttempts must be an integer >= 1");
1974
+ }
1963
1975
  return {
1964
1976
  name: `retry(${tool.name})`,
1965
1977
  description: `${tool.description} (with retry)`,
1966
1978
  invoke: async (input) => {
1967
- let lastError;
1979
+ let lastError = new Error(`Tool ${tool.name} failed without an explicit error`);
1968
1980
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1969
1981
  try {
1970
1982
  return await tool.invoke(input);
1971
1983
  } catch (error) {
1972
- lastError = error;
1984
+ lastError = toError(error);
1973
1985
  if (attempt < maxAttempts) {
1974
- const waitTime = backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1986
+ const waitTime = calculateRetryDelay(attempt, delay, backoff);
1975
1987
  await new Promise((resolve) => setTimeout(resolve, waitTime));
1976
1988
  }
1977
1989
  }
@@ -1985,12 +1997,19 @@ function timeout(tool, ms) {
1985
1997
  name: `timeout(${tool.name})`,
1986
1998
  description: `${tool.description} (with ${ms}ms timeout)`,
1987
1999
  invoke: async (input) => {
1988
- return Promise.race([
1989
- tool.invoke(input),
1990
- new Promise(
1991
- (_, reject) => setTimeout(() => reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`)), ms)
1992
- )
1993
- ]);
2000
+ let timer;
2001
+ const timeoutPromise = new Promise((_, reject) => {
2002
+ timer = setTimeout(() => {
2003
+ reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`));
2004
+ }, ms);
2005
+ });
2006
+ try {
2007
+ return await Promise.race([tool.invoke(input), timeoutPromise]);
2008
+ } finally {
2009
+ if (timer !== void 0) {
2010
+ clearTimeout(timer);
2011
+ }
2012
+ }
1994
2013
  }
1995
2014
  };
1996
2015
  }
package/dist/index.d.cts CHANGED
@@ -1670,54 +1670,57 @@ declare function createManagedTool<TContext = any, TInput = any, TOutput = any>(
1670
1670
  * Tool Composition - Compose tools into higher-level operations
1671
1671
  * @module tools/composition
1672
1672
  */
1673
- interface ComposedTool {
1673
+ type RetryBackoffStrategy = 'linear' | 'exponential';
1674
+ interface RetryOptions$1 {
1675
+ maxAttempts?: number;
1676
+ delay?: number;
1677
+ backoff?: RetryBackoffStrategy;
1678
+ }
1679
+ interface ComposedTool<TInput = unknown, TOutput = unknown> {
1674
1680
  name: string;
1675
1681
  description: string;
1676
- invoke: (input: any) => Promise<any>;
1682
+ invoke(input: TInput): Promise<TOutput>;
1677
1683
  }
1678
- interface ConditionalConfig {
1679
- condition: (input: any) => boolean | Promise<boolean>;
1680
- onTrue: ComposedTool;
1681
- onFalse: ComposedTool;
1684
+ interface ConditionalConfig<TInput = unknown, TTrueOutput = unknown, TFalseOutput = unknown> {
1685
+ condition(input: TInput): boolean | Promise<boolean>;
1686
+ onTrue: ComposedTool<TInput, TTrueOutput>;
1687
+ onFalse: ComposedTool<TInput, TFalseOutput>;
1682
1688
  }
1683
- interface ComposeToolConfig {
1689
+ type ComposedStep = ComposedTool<unknown, unknown> | ComposedTool<unknown, unknown>[] | ConditionalConfig<unknown, unknown, unknown>;
1690
+ interface ComposeToolConfig<TOutput = unknown> {
1684
1691
  name: string;
1685
1692
  description?: string;
1686
- steps: Array<ComposedTool | ComposedTool[] | ConditionalConfig>;
1687
- transformResult?: (result: any) => any;
1693
+ steps: ComposedStep[];
1694
+ transformResult?: (result: unknown) => TOutput;
1688
1695
  }
1689
1696
  /**
1690
1697
  * Execute tools sequentially
1691
1698
  */
1692
- declare function sequential(tools: ComposedTool[]): ComposedTool;
1699
+ declare function sequential<TInput = unknown>(tools: ComposedTool<unknown, unknown>[]): ComposedTool<TInput, unknown>;
1693
1700
  /**
1694
1701
  * Execute tools in parallel
1695
1702
  */
1696
- declare function parallel(tools: ComposedTool[]): ComposedTool;
1703
+ declare function parallel<TInput = unknown>(tools: ComposedTool<TInput, unknown>[]): ComposedTool<TInput, unknown[]>;
1697
1704
  /**
1698
1705
  * Execute tool conditionally
1699
1706
  */
1700
- declare function conditional(config: ConditionalConfig): ComposedTool;
1707
+ declare function conditional<TInput = unknown, TTrueOutput = unknown, TFalseOutput = unknown>(config: ConditionalConfig<TInput, TTrueOutput, TFalseOutput>): ComposedTool<TInput, TTrueOutput | TFalseOutput>;
1701
1708
  /**
1702
1709
  * Compose tools into a complex workflow
1703
1710
  */
1704
- declare function composeTool(config: ComposeToolConfig): ComposedTool;
1711
+ declare function composeTool<TInput = unknown, TOutput = unknown>(config: ComposeToolConfig<TOutput>): ComposedTool<TInput, TOutput>;
1705
1712
  /**
1706
1713
  * Create a tool that retries on failure
1707
1714
  */
1708
- declare function retry(tool: ComposedTool, options?: {
1709
- maxAttempts?: number;
1710
- delay?: number;
1711
- backoff?: 'linear' | 'exponential';
1712
- }): ComposedTool;
1715
+ declare function retry<TInput = unknown, TOutput = unknown>(tool: ComposedTool<TInput, TOutput>, options?: RetryOptions$1): ComposedTool<TInput, TOutput>;
1713
1716
  /**
1714
1717
  * Create a tool that times out
1715
1718
  */
1716
- declare function timeout(tool: ComposedTool, ms: number): ComposedTool;
1719
+ declare function timeout<TInput = unknown, TOutput = unknown>(tool: ComposedTool<TInput, TOutput>, ms: number): ComposedTool<TInput, TOutput>;
1717
1720
  /**
1718
1721
  * Create a tool that caches results
1719
1722
  */
1720
- declare function cache(tool: ComposedTool, ttl?: number): ComposedTool;
1723
+ declare function cache<TInput = unknown, TOutput = unknown>(tool: ComposedTool<TInput, TOutput>, ttl?: number): ComposedTool<TInput, TOutput>;
1721
1724
 
1722
1725
  /**
1723
1726
  * Tool Mocking & Testing - Mock tools for testing
package/dist/index.d.ts CHANGED
@@ -1670,54 +1670,57 @@ declare function createManagedTool<TContext = any, TInput = any, TOutput = any>(
1670
1670
  * Tool Composition - Compose tools into higher-level operations
1671
1671
  * @module tools/composition
1672
1672
  */
1673
- interface ComposedTool {
1673
+ type RetryBackoffStrategy = 'linear' | 'exponential';
1674
+ interface RetryOptions$1 {
1675
+ maxAttempts?: number;
1676
+ delay?: number;
1677
+ backoff?: RetryBackoffStrategy;
1678
+ }
1679
+ interface ComposedTool<TInput = unknown, TOutput = unknown> {
1674
1680
  name: string;
1675
1681
  description: string;
1676
- invoke: (input: any) => Promise<any>;
1682
+ invoke(input: TInput): Promise<TOutput>;
1677
1683
  }
1678
- interface ConditionalConfig {
1679
- condition: (input: any) => boolean | Promise<boolean>;
1680
- onTrue: ComposedTool;
1681
- onFalse: ComposedTool;
1684
+ interface ConditionalConfig<TInput = unknown, TTrueOutput = unknown, TFalseOutput = unknown> {
1685
+ condition(input: TInput): boolean | Promise<boolean>;
1686
+ onTrue: ComposedTool<TInput, TTrueOutput>;
1687
+ onFalse: ComposedTool<TInput, TFalseOutput>;
1682
1688
  }
1683
- interface ComposeToolConfig {
1689
+ type ComposedStep = ComposedTool<unknown, unknown> | ComposedTool<unknown, unknown>[] | ConditionalConfig<unknown, unknown, unknown>;
1690
+ interface ComposeToolConfig<TOutput = unknown> {
1684
1691
  name: string;
1685
1692
  description?: string;
1686
- steps: Array<ComposedTool | ComposedTool[] | ConditionalConfig>;
1687
- transformResult?: (result: any) => any;
1693
+ steps: ComposedStep[];
1694
+ transformResult?: (result: unknown) => TOutput;
1688
1695
  }
1689
1696
  /**
1690
1697
  * Execute tools sequentially
1691
1698
  */
1692
- declare function sequential(tools: ComposedTool[]): ComposedTool;
1699
+ declare function sequential<TInput = unknown>(tools: ComposedTool<unknown, unknown>[]): ComposedTool<TInput, unknown>;
1693
1700
  /**
1694
1701
  * Execute tools in parallel
1695
1702
  */
1696
- declare function parallel(tools: ComposedTool[]): ComposedTool;
1703
+ declare function parallel<TInput = unknown>(tools: ComposedTool<TInput, unknown>[]): ComposedTool<TInput, unknown[]>;
1697
1704
  /**
1698
1705
  * Execute tool conditionally
1699
1706
  */
1700
- declare function conditional(config: ConditionalConfig): ComposedTool;
1707
+ declare function conditional<TInput = unknown, TTrueOutput = unknown, TFalseOutput = unknown>(config: ConditionalConfig<TInput, TTrueOutput, TFalseOutput>): ComposedTool<TInput, TTrueOutput | TFalseOutput>;
1701
1708
  /**
1702
1709
  * Compose tools into a complex workflow
1703
1710
  */
1704
- declare function composeTool(config: ComposeToolConfig): ComposedTool;
1711
+ declare function composeTool<TInput = unknown, TOutput = unknown>(config: ComposeToolConfig<TOutput>): ComposedTool<TInput, TOutput>;
1705
1712
  /**
1706
1713
  * Create a tool that retries on failure
1707
1714
  */
1708
- declare function retry(tool: ComposedTool, options?: {
1709
- maxAttempts?: number;
1710
- delay?: number;
1711
- backoff?: 'linear' | 'exponential';
1712
- }): ComposedTool;
1715
+ declare function retry<TInput = unknown, TOutput = unknown>(tool: ComposedTool<TInput, TOutput>, options?: RetryOptions$1): ComposedTool<TInput, TOutput>;
1713
1716
  /**
1714
1717
  * Create a tool that times out
1715
1718
  */
1716
- declare function timeout(tool: ComposedTool, ms: number): ComposedTool;
1719
+ declare function timeout<TInput = unknown, TOutput = unknown>(tool: ComposedTool<TInput, TOutput>, ms: number): ComposedTool<TInput, TOutput>;
1717
1720
  /**
1718
1721
  * Create a tool that caches results
1719
1722
  */
1720
- declare function cache(tool: ComposedTool, ttl?: number): ComposedTool;
1723
+ declare function cache<TInput = unknown, TOutput = unknown>(tool: ComposedTool<TInput, TOutput>, ttl?: number): ComposedTool<TInput, TOutput>;
1721
1724
 
1722
1725
  /**
1723
1726
  * Tool Mocking & Testing - Mock tools for testing
package/dist/index.js CHANGED
@@ -1391,7 +1391,7 @@ function createToolExecutor(config = {}) {
1391
1391
  }
1392
1392
  return Math.min(delay, maxDelay);
1393
1393
  }
1394
- function toError(error) {
1394
+ function toError2(error) {
1395
1395
  if (error instanceof Error) {
1396
1396
  return error;
1397
1397
  }
@@ -1422,7 +1422,7 @@ function createToolExecutor(config = {}) {
1422
1422
  try {
1423
1423
  return await executeFn.call(tool, input);
1424
1424
  } catch (error) {
1425
- const currentError = toError(error);
1425
+ const currentError = toError2(error);
1426
1426
  lastError = currentError;
1427
1427
  if (policy.retryableErrors && policy.retryableErrors.length > 0) {
1428
1428
  const isRetryable = policy.retryableErrors.some(
@@ -1460,7 +1460,7 @@ function createToolExecutor(config = {}) {
1460
1460
  return result;
1461
1461
  } catch (error) {
1462
1462
  const duration = Date.now() - startTime;
1463
- const normalizedError = toError(error);
1463
+ const normalizedError = toError2(error);
1464
1464
  metrics.totalExecutions++;
1465
1465
  metrics.failedExecutions++;
1466
1466
  metrics.totalDuration += duration;
@@ -1727,6 +1727,15 @@ function createManagedTool(config) {
1727
1727
  }
1728
1728
 
1729
1729
  // src/tools/composition.ts
1730
+ function isConditionalStep(step) {
1731
+ return !Array.isArray(step) && "condition" in step;
1732
+ }
1733
+ function calculateRetryDelay(attempt, delay, backoff) {
1734
+ return backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1735
+ }
1736
+ function toError(error) {
1737
+ return error instanceof Error ? error : new Error(String(error));
1738
+ }
1730
1739
  function sequential(tools) {
1731
1740
  return {
1732
1741
  name: `sequential(${tools.map((t) => t.name).join(" -> ")})`,
@@ -1770,7 +1779,7 @@ function composeTool(config) {
1770
1779
  for (const step of config.steps) {
1771
1780
  if (Array.isArray(step)) {
1772
1781
  result = await parallel(step).invoke(result);
1773
- } else if ("condition" in step) {
1782
+ } else if (isConditionalStep(step)) {
1774
1783
  result = await conditional(step).invoke(result);
1775
1784
  } else {
1776
1785
  result = await step.invoke(result);
@@ -1785,18 +1794,21 @@ function composeTool(config) {
1785
1794
  }
1786
1795
  function retry(tool, options = {}) {
1787
1796
  const { maxAttempts = 3, delay = 1e3, backoff = "exponential" } = options;
1797
+ if (!Number.isInteger(maxAttempts) || maxAttempts < 1) {
1798
+ throw new Error("Invalid retry options: maxAttempts must be an integer >= 1");
1799
+ }
1788
1800
  return {
1789
1801
  name: `retry(${tool.name})`,
1790
1802
  description: `${tool.description} (with retry)`,
1791
1803
  invoke: async (input) => {
1792
- let lastError;
1804
+ let lastError = new Error(`Tool ${tool.name} failed without an explicit error`);
1793
1805
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1794
1806
  try {
1795
1807
  return await tool.invoke(input);
1796
1808
  } catch (error) {
1797
- lastError = error;
1809
+ lastError = toError(error);
1798
1810
  if (attempt < maxAttempts) {
1799
- const waitTime = backoff === "exponential" ? delay * Math.pow(2, attempt - 1) : delay * attempt;
1811
+ const waitTime = calculateRetryDelay(attempt, delay, backoff);
1800
1812
  await new Promise((resolve) => setTimeout(resolve, waitTime));
1801
1813
  }
1802
1814
  }
@@ -1810,12 +1822,19 @@ function timeout(tool, ms) {
1810
1822
  name: `timeout(${tool.name})`,
1811
1823
  description: `${tool.description} (with ${ms}ms timeout)`,
1812
1824
  invoke: async (input) => {
1813
- return Promise.race([
1814
- tool.invoke(input),
1815
- new Promise(
1816
- (_, reject) => setTimeout(() => reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`)), ms)
1817
- )
1818
- ]);
1825
+ let timer;
1826
+ const timeoutPromise = new Promise((_, reject) => {
1827
+ timer = setTimeout(() => {
1828
+ reject(new Error(`Tool ${tool.name} timed out after ${ms}ms`));
1829
+ }, ms);
1830
+ });
1831
+ try {
1832
+ return await Promise.race([tool.invoke(input), timeoutPromise]);
1833
+ } finally {
1834
+ if (timer !== void 0) {
1835
+ clearTimeout(timer);
1836
+ }
1837
+ }
1819
1838
  }
1820
1839
  };
1821
1840
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/core",
3
- "version": "0.15.4",
3
+ "version": "0.15.6",
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",