@agentforge/core 0.16.17 → 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 +235 -115
- package/dist/index.d.cts +48 -33
- package/dist/index.d.ts +48 -33
- package/dist/index.js +235 -115
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -991,6 +991,79 @@ function emitRegistryEvent(eventHandlers, event, data) {
|
|
|
991
991
|
});
|
|
992
992
|
}
|
|
993
993
|
|
|
994
|
+
// src/tools/registry-mutations.ts
|
|
995
|
+
function eraseToolType(tool) {
|
|
996
|
+
return tool;
|
|
997
|
+
}
|
|
998
|
+
function registerRegistryTool(tools, tool, emit, events) {
|
|
999
|
+
const name = tool.metadata.name;
|
|
1000
|
+
if (tools.has(name)) {
|
|
1001
|
+
throw new Error(
|
|
1002
|
+
`Tool with name "${name}" is already registered. Use update() to modify it.`
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
tools.set(name, eraseToolType(tool));
|
|
1006
|
+
emit(events.registered, tool);
|
|
1007
|
+
}
|
|
1008
|
+
function removeRegistryTool(tools, name, emit, events) {
|
|
1009
|
+
const tool = tools.get(name);
|
|
1010
|
+
if (!tool) {
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
tools.delete(name);
|
|
1014
|
+
emit(events.removed, tool);
|
|
1015
|
+
return true;
|
|
1016
|
+
}
|
|
1017
|
+
function updateRegistryTool(tools, name, tool, emit, events) {
|
|
1018
|
+
if (!tools.has(name)) {
|
|
1019
|
+
return false;
|
|
1020
|
+
}
|
|
1021
|
+
if (tool.metadata.name !== name) {
|
|
1022
|
+
throw new Error(
|
|
1023
|
+
`Cannot update tool: metadata.name "${tool.metadata.name}" does not match registry key "${name}". To rename a tool, remove it and register it again with the new name.`
|
|
1024
|
+
);
|
|
1025
|
+
}
|
|
1026
|
+
tools.set(name, eraseToolType(tool));
|
|
1027
|
+
emit(events.updated, { name, tool });
|
|
1028
|
+
return true;
|
|
1029
|
+
}
|
|
1030
|
+
function registerManyRegistryTools(tools, toolsToRegister, emit, events) {
|
|
1031
|
+
const pendingTools = Array.from(toolsToRegister);
|
|
1032
|
+
const inputNames = /* @__PURE__ */ new Set();
|
|
1033
|
+
const duplicatesInInput = [];
|
|
1034
|
+
for (const tool of pendingTools) {
|
|
1035
|
+
const name = tool.metadata.name;
|
|
1036
|
+
if (inputNames.has(name)) {
|
|
1037
|
+
duplicatesInInput.push(name);
|
|
1038
|
+
} else {
|
|
1039
|
+
inputNames.add(name);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
if (duplicatesInInput.length > 0) {
|
|
1043
|
+
throw new Error(
|
|
1044
|
+
`Cannot register tools: duplicate names in input list: ${duplicatesInInput.join(", ")}`
|
|
1045
|
+
);
|
|
1046
|
+
}
|
|
1047
|
+
const conflicts = [];
|
|
1048
|
+
for (const tool of pendingTools) {
|
|
1049
|
+
if (tools.has(tool.metadata.name)) {
|
|
1050
|
+
conflicts.push(tool.metadata.name);
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
if (conflicts.length > 0) {
|
|
1054
|
+
throw new Error(
|
|
1055
|
+
`Cannot register tools: the following names already exist: ${conflicts.join(", ")}`
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
for (const tool of pendingTools) {
|
|
1059
|
+
registerRegistryTool(tools, tool, emit, events);
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
function clearRegistryTools(tools, emit, events) {
|
|
1063
|
+
tools.clear();
|
|
1064
|
+
emit(events.cleared, null);
|
|
1065
|
+
}
|
|
1066
|
+
|
|
994
1067
|
// src/tools/registry-prompt.ts
|
|
995
1068
|
var import_zod3 = require("zod");
|
|
996
1069
|
|
|
@@ -1261,33 +1334,31 @@ var RegistryEvent = /* @__PURE__ */ ((RegistryEvent2) => {
|
|
|
1261
1334
|
RegistryEvent2["REGISTRY_CLEARED"] = "registry:cleared";
|
|
1262
1335
|
return RegistryEvent2;
|
|
1263
1336
|
})(RegistryEvent || {});
|
|
1264
|
-
function eraseToolType(tool) {
|
|
1265
|
-
return tool;
|
|
1266
|
-
}
|
|
1267
1337
|
var ToolRegistry = class {
|
|
1268
1338
|
tools = /* @__PURE__ */ new Map();
|
|
1269
1339
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
1340
|
+
mutationEvents = {
|
|
1341
|
+
registered: "tool:registered" /* TOOL_REGISTERED */,
|
|
1342
|
+
removed: "tool:removed" /* TOOL_REMOVED */,
|
|
1343
|
+
updated: "tool:updated" /* TOOL_UPDATED */,
|
|
1344
|
+
cleared: "registry:cleared" /* REGISTRY_CLEARED */
|
|
1345
|
+
};
|
|
1346
|
+
emitMutation = (event, data) => {
|
|
1347
|
+
this.emit(event, data);
|
|
1348
|
+
};
|
|
1270
1349
|
/**
|
|
1271
1350
|
* Register a tool in the registry
|
|
1272
1351
|
*
|
|
1273
1352
|
* @param tool - The tool to register
|
|
1274
1353
|
* @throws Error if a tool with the same name already exists
|
|
1275
1354
|
*
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1355
|
+
* @example
|
|
1356
|
+
* ```ts
|
|
1357
|
+
* registry.register(readFileTool);
|
|
1279
1358
|
* ```
|
|
1280
1359
|
*/
|
|
1281
1360
|
register(tool) {
|
|
1282
|
-
|
|
1283
|
-
const name = tool.metadata.name;
|
|
1284
|
-
if (this.tools.has(name)) {
|
|
1285
|
-
throw new Error(
|
|
1286
|
-
`Tool with name "${name}" is already registered. Use update() to modify it.`
|
|
1287
|
-
);
|
|
1288
|
-
}
|
|
1289
|
-
this.tools.set(name, erasedTool);
|
|
1290
|
-
this.emit("tool:registered" /* TOOL_REGISTERED */, tool);
|
|
1361
|
+
registerRegistryTool(this.tools, tool, this.emitMutation, this.mutationEvents);
|
|
1291
1362
|
}
|
|
1292
1363
|
/**
|
|
1293
1364
|
* Get a tool by name
|
|
@@ -1328,20 +1399,14 @@ var ToolRegistry = class {
|
|
|
1328
1399
|
* @param name - The tool name
|
|
1329
1400
|
* @returns True if the tool was removed, false if it didn't exist
|
|
1330
1401
|
*
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1402
|
+
* @example
|
|
1403
|
+
* ```ts
|
|
1404
|
+
* const removed = registry.remove('read-file');
|
|
1405
|
+
* console.log(removed ? 'Removed' : 'Not found');
|
|
1335
1406
|
* ```
|
|
1336
1407
|
*/
|
|
1337
1408
|
remove(name) {
|
|
1338
|
-
|
|
1339
|
-
if (!tool) {
|
|
1340
|
-
return false;
|
|
1341
|
-
}
|
|
1342
|
-
this.tools.delete(name);
|
|
1343
|
-
this.emit("tool:removed" /* TOOL_REMOVED */, tool);
|
|
1344
|
-
return true;
|
|
1409
|
+
return removeRegistryTool(this.tools, name, this.emitMutation, this.mutationEvents);
|
|
1345
1410
|
}
|
|
1346
1411
|
/**
|
|
1347
1412
|
* Update an existing tool
|
|
@@ -1351,24 +1416,13 @@ var ToolRegistry = class {
|
|
|
1351
1416
|
* @returns True if updated, false if the tool didn't exist
|
|
1352
1417
|
* @throws Error if the tool's metadata.name doesn't match the name parameter
|
|
1353
1418
|
*
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1419
|
+
* @example
|
|
1420
|
+
* ```ts
|
|
1421
|
+
* const updated = registry.update('read-file', newReadFileTool);
|
|
1357
1422
|
* ```
|
|
1358
1423
|
*/
|
|
1359
1424
|
update(name, tool) {
|
|
1360
|
-
|
|
1361
|
-
if (!this.tools.has(name)) {
|
|
1362
|
-
return false;
|
|
1363
|
-
}
|
|
1364
|
-
if (tool.metadata.name !== name) {
|
|
1365
|
-
throw new Error(
|
|
1366
|
-
`Cannot update tool: metadata.name "${tool.metadata.name}" does not match registry key "${name}". To rename a tool, remove it and register it again with the new name.`
|
|
1367
|
-
);
|
|
1368
|
-
}
|
|
1369
|
-
this.tools.set(name, erasedTool);
|
|
1370
|
-
this.emit("tool:updated" /* TOOL_UPDATED */, { name, tool });
|
|
1371
|
-
return true;
|
|
1425
|
+
return updateRegistryTool(this.tools, name, tool, this.emitMutation, this.mutationEvents);
|
|
1372
1426
|
}
|
|
1373
1427
|
/**
|
|
1374
1428
|
* Get all registered tools
|
|
@@ -1435,55 +1489,25 @@ var ToolRegistry = class {
|
|
|
1435
1489
|
* @param tools - Iterable of tools to register
|
|
1436
1490
|
* @throws Error if any tool name conflicts with existing tools
|
|
1437
1491
|
*
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1492
|
+
* @example
|
|
1493
|
+
* ```ts
|
|
1494
|
+
* registry.registerMany([tool1, tool2, tool3]);
|
|
1441
1495
|
* ```
|
|
1442
1496
|
*/
|
|
1443
1497
|
registerMany(tools) {
|
|
1444
|
-
|
|
1445
|
-
const inputNames = /* @__PURE__ */ new Set();
|
|
1446
|
-
const duplicatesInInput = [];
|
|
1447
|
-
for (const tool of toolsToRegister) {
|
|
1448
|
-
const name = tool.metadata.name;
|
|
1449
|
-
if (inputNames.has(name)) {
|
|
1450
|
-
duplicatesInInput.push(name);
|
|
1451
|
-
} else {
|
|
1452
|
-
inputNames.add(name);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
if (duplicatesInInput.length > 0) {
|
|
1456
|
-
throw new Error(
|
|
1457
|
-
`Cannot register tools: duplicate names in input list: ${duplicatesInInput.join(", ")}`
|
|
1458
|
-
);
|
|
1459
|
-
}
|
|
1460
|
-
const conflicts = [];
|
|
1461
|
-
for (const tool of toolsToRegister) {
|
|
1462
|
-
if (this.tools.has(tool.metadata.name)) {
|
|
1463
|
-
conflicts.push(tool.metadata.name);
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
if (conflicts.length > 0) {
|
|
1467
|
-
throw new Error(
|
|
1468
|
-
`Cannot register tools: the following names already exist: ${conflicts.join(", ")}`
|
|
1469
|
-
);
|
|
1470
|
-
}
|
|
1471
|
-
for (const tool of toolsToRegister) {
|
|
1472
|
-
this.register(tool);
|
|
1473
|
-
}
|
|
1498
|
+
registerManyRegistryTools(this.tools, tools, this.emitMutation, this.mutationEvents);
|
|
1474
1499
|
}
|
|
1475
1500
|
/**
|
|
1476
1501
|
* Clear all tools from the registry
|
|
1477
1502
|
*
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1503
|
+
* @example
|
|
1504
|
+
* ```ts
|
|
1505
|
+
* registry.clear();
|
|
1506
|
+
* console.log(registry.size()); // 0
|
|
1482
1507
|
* ```
|
|
1483
1508
|
*/
|
|
1484
1509
|
clear() {
|
|
1485
|
-
this.tools.
|
|
1486
|
-
this.emit("registry:cleared" /* REGISTRY_CLEARED */, null);
|
|
1510
|
+
clearRegistryTools(this.tools, this.emitMutation, this.mutationEvents);
|
|
1487
1511
|
}
|
|
1488
1512
|
/**
|
|
1489
1513
|
* Get the number of registered tools
|
|
@@ -1822,6 +1846,12 @@ var ManagedTool = class {
|
|
|
1822
1846
|
failedExecutions: 0
|
|
1823
1847
|
};
|
|
1824
1848
|
_healthCheckTimer;
|
|
1849
|
+
_beforeExitHandler;
|
|
1850
|
+
_healthCheckInFlight = false;
|
|
1851
|
+
_cleaningUp = false;
|
|
1852
|
+
_cleanupPromise;
|
|
1853
|
+
_initializePromise;
|
|
1854
|
+
_lifecycleGeneration = 0;
|
|
1825
1855
|
constructor(config) {
|
|
1826
1856
|
this.name = config.name;
|
|
1827
1857
|
this.description = config.description;
|
|
@@ -1832,17 +1862,7 @@ var ManagedTool = class {
|
|
|
1832
1862
|
this.autoCleanup = config.autoCleanup ?? true;
|
|
1833
1863
|
this.healthCheckInterval = config.healthCheckInterval;
|
|
1834
1864
|
this._context = config.context;
|
|
1835
|
-
|
|
1836
|
-
process.on("beforeExit", () => {
|
|
1837
|
-
this.cleanup().catch(
|
|
1838
|
-
(err) => logger3.error("Cleanup failed", {
|
|
1839
|
-
toolName: this.name,
|
|
1840
|
-
error: err instanceof Error ? err.message : String(err),
|
|
1841
|
-
...err instanceof Error && err.stack ? { stack: err.stack } : {}
|
|
1842
|
-
})
|
|
1843
|
-
);
|
|
1844
|
-
});
|
|
1845
|
-
}
|
|
1865
|
+
this.ensureBeforeExitHandler();
|
|
1846
1866
|
}
|
|
1847
1867
|
/**
|
|
1848
1868
|
* Get the tool context (e.g., connection pool, API client)
|
|
@@ -1866,28 +1886,26 @@ var ManagedTool = class {
|
|
|
1866
1886
|
* Initialize the tool
|
|
1867
1887
|
*/
|
|
1868
1888
|
async initialize() {
|
|
1869
|
-
if (this.
|
|
1889
|
+
if (this._initializePromise) {
|
|
1890
|
+
await this._initializePromise;
|
|
1870
1891
|
return;
|
|
1871
1892
|
}
|
|
1872
|
-
if (this.
|
|
1873
|
-
await this.
|
|
1893
|
+
if (this._cleanupPromise) {
|
|
1894
|
+
await this._cleanupPromise;
|
|
1895
|
+
if (this._initializePromise) {
|
|
1896
|
+
await this._initializePromise;
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1874
1899
|
}
|
|
1875
|
-
this._initialized
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
this._stats.lastHealthCheck = {
|
|
1885
|
-
healthy: false,
|
|
1886
|
-
error: error.message
|
|
1887
|
-
};
|
|
1888
|
-
this._stats.lastHealthCheckTime = Date.now();
|
|
1889
|
-
}
|
|
1890
|
-
}, 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;
|
|
1891
1909
|
}
|
|
1892
1910
|
}
|
|
1893
1911
|
/**
|
|
@@ -1914,24 +1932,55 @@ var ManagedTool = class {
|
|
|
1914
1932
|
* Cleanup the tool
|
|
1915
1933
|
*/
|
|
1916
1934
|
async cleanup() {
|
|
1917
|
-
if (
|
|
1935
|
+
if (this._cleanupPromise) {
|
|
1936
|
+
await this._cleanupPromise;
|
|
1918
1937
|
return;
|
|
1919
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;
|
|
1920
1955
|
if (this._healthCheckTimer) {
|
|
1921
1956
|
clearInterval(this._healthCheckTimer);
|
|
1922
1957
|
this._healthCheckTimer = void 0;
|
|
1923
1958
|
}
|
|
1924
|
-
if (this.
|
|
1925
|
-
|
|
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;
|
|
1926
1966
|
}
|
|
1927
1967
|
this._initialized = false;
|
|
1928
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;
|
|
1929
1978
|
}
|
|
1930
1979
|
/**
|
|
1931
1980
|
* Run health check
|
|
1932
1981
|
*/
|
|
1933
1982
|
async healthCheck() {
|
|
1934
|
-
if (!this._initialized) {
|
|
1983
|
+
if (!this._initialized || this._cleaningUp) {
|
|
1935
1984
|
return {
|
|
1936
1985
|
healthy: false,
|
|
1937
1986
|
error: "Tool is not initialized"
|
|
@@ -1943,15 +1992,28 @@ var ManagedTool = class {
|
|
|
1943
1992
|
metadata: { message: "No health check configured" }
|
|
1944
1993
|
};
|
|
1945
1994
|
}
|
|
1995
|
+
const lifecycleGeneration = this._lifecycleGeneration;
|
|
1946
1996
|
try {
|
|
1947
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
|
+
}
|
|
1948
2004
|
this._stats.lastHealthCheck = result;
|
|
1949
2005
|
this._stats.lastHealthCheckTime = Date.now();
|
|
1950
2006
|
return result;
|
|
1951
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
|
+
}
|
|
1952
2014
|
const result = {
|
|
1953
2015
|
healthy: false,
|
|
1954
|
-
error: error
|
|
2016
|
+
error: getErrorMessage(error)
|
|
1955
2017
|
};
|
|
1956
2018
|
this._stats.lastHealthCheck = result;
|
|
1957
2019
|
this._stats.lastHealthCheckTime = Date.now();
|
|
@@ -1985,10 +2047,68 @@ var ManagedTool = class {
|
|
|
1985
2047
|
}
|
|
1986
2048
|
};
|
|
1987
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
|
+
}
|
|
1988
2105
|
};
|
|
1989
2106
|
function createManagedTool(config) {
|
|
1990
2107
|
return new ManagedTool(config);
|
|
1991
2108
|
}
|
|
2109
|
+
function getErrorMessage(error) {
|
|
2110
|
+
return error instanceof Error ? error.message : String(error);
|
|
2111
|
+
}
|
|
1992
2112
|
|
|
1993
2113
|
// src/tools/composition.ts
|
|
1994
2114
|
function isConditionalStep(step) {
|
package/dist/index.d.cts
CHANGED
|
@@ -1257,15 +1257,17 @@ interface PromptOptions extends RegistryPromptOptions {
|
|
|
1257
1257
|
declare class ToolRegistry {
|
|
1258
1258
|
private tools;
|
|
1259
1259
|
private eventHandlers;
|
|
1260
|
+
private readonly mutationEvents;
|
|
1261
|
+
private readonly emitMutation;
|
|
1260
1262
|
/**
|
|
1261
1263
|
* Register a tool in the registry
|
|
1262
1264
|
*
|
|
1263
1265
|
* @param tool - The tool to register
|
|
1264
1266
|
* @throws Error if a tool with the same name already exists
|
|
1265
1267
|
*
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1268
|
+
* @example
|
|
1269
|
+
* ```ts
|
|
1270
|
+
* registry.register(readFileTool);
|
|
1269
1271
|
* ```
|
|
1270
1272
|
*/
|
|
1271
1273
|
register<TInput, TOutput>(tool: Tool<TInput, TOutput>): void;
|
|
@@ -1304,10 +1306,10 @@ declare class ToolRegistry {
|
|
|
1304
1306
|
* @param name - The tool name
|
|
1305
1307
|
* @returns True if the tool was removed, false if it didn't exist
|
|
1306
1308
|
*
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1309
|
+
* @example
|
|
1310
|
+
* ```ts
|
|
1311
|
+
* const removed = registry.remove('read-file');
|
|
1312
|
+
* console.log(removed ? 'Removed' : 'Not found');
|
|
1311
1313
|
* ```
|
|
1312
1314
|
*/
|
|
1313
1315
|
remove(name: string): boolean;
|
|
@@ -1319,9 +1321,9 @@ declare class ToolRegistry {
|
|
|
1319
1321
|
* @returns True if updated, false if the tool didn't exist
|
|
1320
1322
|
* @throws Error if the tool's metadata.name doesn't match the name parameter
|
|
1321
1323
|
*
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1324
|
+
* @example
|
|
1325
|
+
* ```ts
|
|
1326
|
+
* const updated = registry.update('read-file', newReadFileTool);
|
|
1325
1327
|
* ```
|
|
1326
1328
|
*/
|
|
1327
1329
|
update<TInput, TOutput>(name: string, tool: Tool<TInput, TOutput>): boolean;
|
|
@@ -1382,19 +1384,19 @@ declare class ToolRegistry {
|
|
|
1382
1384
|
* @param tools - Iterable of tools to register
|
|
1383
1385
|
* @throws Error if any tool name conflicts with existing tools
|
|
1384
1386
|
*
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1387
|
+
* @example
|
|
1388
|
+
* ```ts
|
|
1389
|
+
* registry.registerMany([tool1, tool2, tool3]);
|
|
1388
1390
|
* ```
|
|
1389
1391
|
*/
|
|
1390
1392
|
registerMany(tools: Iterable<RegisterManyTool>): void;
|
|
1391
1393
|
/**
|
|
1392
1394
|
* Clear all tools from the registry
|
|
1393
1395
|
*
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1396
|
+
* @example
|
|
1397
|
+
* ```ts
|
|
1398
|
+
* registry.clear();
|
|
1399
|
+
* console.log(registry.size()); // 0
|
|
1398
1400
|
* ```
|
|
1399
1401
|
*/
|
|
1400
1402
|
clear(): void;
|
|
@@ -1568,26 +1570,38 @@ declare function createToolExecutor(config?: ToolExecutorConfig): {
|
|
|
1568
1570
|
};
|
|
1569
1571
|
};
|
|
1570
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
|
+
|
|
1571
1582
|
/**
|
|
1572
1583
|
* Tool Lifecycle Management - Manage tool initialization, cleanup, and resources
|
|
1573
1584
|
* @module tools/lifecycle
|
|
1574
1585
|
*/
|
|
1586
|
+
|
|
1575
1587
|
interface ToolHealthCheckResult {
|
|
1576
1588
|
healthy: boolean;
|
|
1577
1589
|
error?: string;
|
|
1578
|
-
metadata?:
|
|
1590
|
+
metadata?: JsonObject;
|
|
1579
1591
|
}
|
|
1580
|
-
interface
|
|
1592
|
+
interface ManagedToolConfigBase<TContext, TInput, TOutput> {
|
|
1581
1593
|
name: string;
|
|
1582
1594
|
description: string;
|
|
1583
1595
|
initialize?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
|
|
1584
1596
|
execute: (this: ManagedTool<TContext, TInput, TOutput>, input: TInput) => Promise<TOutput>;
|
|
1585
1597
|
cleanup?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
|
|
1586
1598
|
healthCheck?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<ToolHealthCheckResult>;
|
|
1587
|
-
context?: TContext;
|
|
1588
1599
|
autoCleanup?: boolean;
|
|
1589
1600
|
healthCheckInterval?: number;
|
|
1590
1601
|
}
|
|
1602
|
+
interface ManagedToolConfig<TContext = undefined, TInput = unknown, TOutput = unknown> extends ManagedToolConfigBase<TContext, TInput, TOutput> {
|
|
1603
|
+
context?: TContext;
|
|
1604
|
+
}
|
|
1591
1605
|
interface ManagedToolStats {
|
|
1592
1606
|
initialized: boolean;
|
|
1593
1607
|
totalExecutions: number;
|
|
@@ -1600,7 +1614,7 @@ interface ManagedToolStats {
|
|
|
1600
1614
|
/**
|
|
1601
1615
|
* Managed tool with lifecycle hooks
|
|
1602
1616
|
*/
|
|
1603
|
-
declare class ManagedTool<TContext =
|
|
1617
|
+
declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown> {
|
|
1604
1618
|
readonly name: string;
|
|
1605
1619
|
readonly description: string;
|
|
1606
1620
|
private readonly initializeFn?;
|
|
@@ -1613,15 +1627,21 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
|
|
|
1613
1627
|
private _context;
|
|
1614
1628
|
private _stats;
|
|
1615
1629
|
private _healthCheckTimer?;
|
|
1630
|
+
private _beforeExitHandler?;
|
|
1631
|
+
private _healthCheckInFlight;
|
|
1632
|
+
private _cleaningUp;
|
|
1633
|
+
private _cleanupPromise?;
|
|
1634
|
+
private _initializePromise?;
|
|
1635
|
+
private _lifecycleGeneration;
|
|
1616
1636
|
constructor(config: ManagedToolConfig<TContext, TInput, TOutput>);
|
|
1617
1637
|
/**
|
|
1618
1638
|
* Get the tool context (e.g., connection pool, API client)
|
|
1619
1639
|
*/
|
|
1620
|
-
get context(): TContext;
|
|
1640
|
+
get context(): TContext | undefined;
|
|
1621
1641
|
/**
|
|
1622
1642
|
* Set the tool context
|
|
1623
1643
|
*/
|
|
1624
|
-
set context(value: TContext);
|
|
1644
|
+
set context(value: TContext | undefined);
|
|
1625
1645
|
/**
|
|
1626
1646
|
* Check if tool is initialized
|
|
1627
1647
|
*/
|
|
@@ -1638,6 +1658,7 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
|
|
|
1638
1658
|
* Cleanup the tool
|
|
1639
1659
|
*/
|
|
1640
1660
|
cleanup(): Promise<void>;
|
|
1661
|
+
private performCleanup;
|
|
1641
1662
|
/**
|
|
1642
1663
|
* Run health check
|
|
1643
1664
|
*/
|
|
@@ -1658,11 +1679,14 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
|
|
|
1658
1679
|
description: string;
|
|
1659
1680
|
invoke: (input: TInput) => Promise<TOutput>;
|
|
1660
1681
|
};
|
|
1682
|
+
private runPeriodicHealthCheck;
|
|
1683
|
+
private performInitialize;
|
|
1684
|
+
private ensureBeforeExitHandler;
|
|
1661
1685
|
}
|
|
1662
1686
|
/**
|
|
1663
1687
|
* Create a managed tool
|
|
1664
1688
|
*/
|
|
1665
|
-
declare function createManagedTool<TContext =
|
|
1689
|
+
declare function createManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
|
|
1666
1690
|
|
|
1667
1691
|
/**
|
|
1668
1692
|
* Tool Composition - Compose tools into higher-level operations
|
|
@@ -2813,15 +2837,6 @@ interface ErrorHandlerOptions<State> {
|
|
|
2813
2837
|
*/
|
|
2814
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>>;
|
|
2815
2839
|
|
|
2816
|
-
/**
|
|
2817
|
-
* Shared JSON-safe payload contracts for observability and monitoring paths.
|
|
2818
|
-
*/
|
|
2819
|
-
type JsonPrimitive = string | number | boolean | null;
|
|
2820
|
-
type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
2821
|
-
interface JsonObject {
|
|
2822
|
-
[key: string]: JsonValue;
|
|
2823
|
-
}
|
|
2824
|
-
|
|
2825
2840
|
/**
|
|
2826
2841
|
* Structured Logging Utilities
|
|
2827
2842
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -1257,15 +1257,17 @@ interface PromptOptions extends RegistryPromptOptions {
|
|
|
1257
1257
|
declare class ToolRegistry {
|
|
1258
1258
|
private tools;
|
|
1259
1259
|
private eventHandlers;
|
|
1260
|
+
private readonly mutationEvents;
|
|
1261
|
+
private readonly emitMutation;
|
|
1260
1262
|
/**
|
|
1261
1263
|
* Register a tool in the registry
|
|
1262
1264
|
*
|
|
1263
1265
|
* @param tool - The tool to register
|
|
1264
1266
|
* @throws Error if a tool with the same name already exists
|
|
1265
1267
|
*
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1268
|
+
* @example
|
|
1269
|
+
* ```ts
|
|
1270
|
+
* registry.register(readFileTool);
|
|
1269
1271
|
* ```
|
|
1270
1272
|
*/
|
|
1271
1273
|
register<TInput, TOutput>(tool: Tool<TInput, TOutput>): void;
|
|
@@ -1304,10 +1306,10 @@ declare class ToolRegistry {
|
|
|
1304
1306
|
* @param name - The tool name
|
|
1305
1307
|
* @returns True if the tool was removed, false if it didn't exist
|
|
1306
1308
|
*
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1309
|
+
* @example
|
|
1310
|
+
* ```ts
|
|
1311
|
+
* const removed = registry.remove('read-file');
|
|
1312
|
+
* console.log(removed ? 'Removed' : 'Not found');
|
|
1311
1313
|
* ```
|
|
1312
1314
|
*/
|
|
1313
1315
|
remove(name: string): boolean;
|
|
@@ -1319,9 +1321,9 @@ declare class ToolRegistry {
|
|
|
1319
1321
|
* @returns True if updated, false if the tool didn't exist
|
|
1320
1322
|
* @throws Error if the tool's metadata.name doesn't match the name parameter
|
|
1321
1323
|
*
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1324
|
+
* @example
|
|
1325
|
+
* ```ts
|
|
1326
|
+
* const updated = registry.update('read-file', newReadFileTool);
|
|
1325
1327
|
* ```
|
|
1326
1328
|
*/
|
|
1327
1329
|
update<TInput, TOutput>(name: string, tool: Tool<TInput, TOutput>): boolean;
|
|
@@ -1382,19 +1384,19 @@ declare class ToolRegistry {
|
|
|
1382
1384
|
* @param tools - Iterable of tools to register
|
|
1383
1385
|
* @throws Error if any tool name conflicts with existing tools
|
|
1384
1386
|
*
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1387
|
+
* @example
|
|
1388
|
+
* ```ts
|
|
1389
|
+
* registry.registerMany([tool1, tool2, tool3]);
|
|
1388
1390
|
* ```
|
|
1389
1391
|
*/
|
|
1390
1392
|
registerMany(tools: Iterable<RegisterManyTool>): void;
|
|
1391
1393
|
/**
|
|
1392
1394
|
* Clear all tools from the registry
|
|
1393
1395
|
*
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1396
|
+
* @example
|
|
1397
|
+
* ```ts
|
|
1398
|
+
* registry.clear();
|
|
1399
|
+
* console.log(registry.size()); // 0
|
|
1398
1400
|
* ```
|
|
1399
1401
|
*/
|
|
1400
1402
|
clear(): void;
|
|
@@ -1568,26 +1570,38 @@ declare function createToolExecutor(config?: ToolExecutorConfig): {
|
|
|
1568
1570
|
};
|
|
1569
1571
|
};
|
|
1570
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
|
+
|
|
1571
1582
|
/**
|
|
1572
1583
|
* Tool Lifecycle Management - Manage tool initialization, cleanup, and resources
|
|
1573
1584
|
* @module tools/lifecycle
|
|
1574
1585
|
*/
|
|
1586
|
+
|
|
1575
1587
|
interface ToolHealthCheckResult {
|
|
1576
1588
|
healthy: boolean;
|
|
1577
1589
|
error?: string;
|
|
1578
|
-
metadata?:
|
|
1590
|
+
metadata?: JsonObject;
|
|
1579
1591
|
}
|
|
1580
|
-
interface
|
|
1592
|
+
interface ManagedToolConfigBase<TContext, TInput, TOutput> {
|
|
1581
1593
|
name: string;
|
|
1582
1594
|
description: string;
|
|
1583
1595
|
initialize?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
|
|
1584
1596
|
execute: (this: ManagedTool<TContext, TInput, TOutput>, input: TInput) => Promise<TOutput>;
|
|
1585
1597
|
cleanup?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<void>;
|
|
1586
1598
|
healthCheck?: (this: ManagedTool<TContext, TInput, TOutput>) => Promise<ToolHealthCheckResult>;
|
|
1587
|
-
context?: TContext;
|
|
1588
1599
|
autoCleanup?: boolean;
|
|
1589
1600
|
healthCheckInterval?: number;
|
|
1590
1601
|
}
|
|
1602
|
+
interface ManagedToolConfig<TContext = undefined, TInput = unknown, TOutput = unknown> extends ManagedToolConfigBase<TContext, TInput, TOutput> {
|
|
1603
|
+
context?: TContext;
|
|
1604
|
+
}
|
|
1591
1605
|
interface ManagedToolStats {
|
|
1592
1606
|
initialized: boolean;
|
|
1593
1607
|
totalExecutions: number;
|
|
@@ -1600,7 +1614,7 @@ interface ManagedToolStats {
|
|
|
1600
1614
|
/**
|
|
1601
1615
|
* Managed tool with lifecycle hooks
|
|
1602
1616
|
*/
|
|
1603
|
-
declare class ManagedTool<TContext =
|
|
1617
|
+
declare class ManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown> {
|
|
1604
1618
|
readonly name: string;
|
|
1605
1619
|
readonly description: string;
|
|
1606
1620
|
private readonly initializeFn?;
|
|
@@ -1613,15 +1627,21 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
|
|
|
1613
1627
|
private _context;
|
|
1614
1628
|
private _stats;
|
|
1615
1629
|
private _healthCheckTimer?;
|
|
1630
|
+
private _beforeExitHandler?;
|
|
1631
|
+
private _healthCheckInFlight;
|
|
1632
|
+
private _cleaningUp;
|
|
1633
|
+
private _cleanupPromise?;
|
|
1634
|
+
private _initializePromise?;
|
|
1635
|
+
private _lifecycleGeneration;
|
|
1616
1636
|
constructor(config: ManagedToolConfig<TContext, TInput, TOutput>);
|
|
1617
1637
|
/**
|
|
1618
1638
|
* Get the tool context (e.g., connection pool, API client)
|
|
1619
1639
|
*/
|
|
1620
|
-
get context(): TContext;
|
|
1640
|
+
get context(): TContext | undefined;
|
|
1621
1641
|
/**
|
|
1622
1642
|
* Set the tool context
|
|
1623
1643
|
*/
|
|
1624
|
-
set context(value: TContext);
|
|
1644
|
+
set context(value: TContext | undefined);
|
|
1625
1645
|
/**
|
|
1626
1646
|
* Check if tool is initialized
|
|
1627
1647
|
*/
|
|
@@ -1638,6 +1658,7 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
|
|
|
1638
1658
|
* Cleanup the tool
|
|
1639
1659
|
*/
|
|
1640
1660
|
cleanup(): Promise<void>;
|
|
1661
|
+
private performCleanup;
|
|
1641
1662
|
/**
|
|
1642
1663
|
* Run health check
|
|
1643
1664
|
*/
|
|
@@ -1658,11 +1679,14 @@ declare class ManagedTool<TContext = any, TInput = any, TOutput = any> {
|
|
|
1658
1679
|
description: string;
|
|
1659
1680
|
invoke: (input: TInput) => Promise<TOutput>;
|
|
1660
1681
|
};
|
|
1682
|
+
private runPeriodicHealthCheck;
|
|
1683
|
+
private performInitialize;
|
|
1684
|
+
private ensureBeforeExitHandler;
|
|
1661
1685
|
}
|
|
1662
1686
|
/**
|
|
1663
1687
|
* Create a managed tool
|
|
1664
1688
|
*/
|
|
1665
|
-
declare function createManagedTool<TContext =
|
|
1689
|
+
declare function createManagedTool<TContext = undefined, TInput = unknown, TOutput = unknown>(config: ManagedToolConfig<TContext, TInput, TOutput>): ManagedTool<TContext, TInput, TOutput>;
|
|
1666
1690
|
|
|
1667
1691
|
/**
|
|
1668
1692
|
* Tool Composition - Compose tools into higher-level operations
|
|
@@ -2813,15 +2837,6 @@ interface ErrorHandlerOptions<State> {
|
|
|
2813
2837
|
*/
|
|
2814
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>>;
|
|
2815
2839
|
|
|
2816
|
-
/**
|
|
2817
|
-
* Shared JSON-safe payload contracts for observability and monitoring paths.
|
|
2818
|
-
*/
|
|
2819
|
-
type JsonPrimitive = string | number | boolean | null;
|
|
2820
|
-
type JsonValue = JsonPrimitive | JsonObject | JsonValue[];
|
|
2821
|
-
interface JsonObject {
|
|
2822
|
-
[key: string]: JsonValue;
|
|
2823
|
-
}
|
|
2824
|
-
|
|
2825
2840
|
/**
|
|
2826
2841
|
* Structured Logging Utilities
|
|
2827
2842
|
*
|
package/dist/index.js
CHANGED
|
@@ -816,6 +816,79 @@ function emitRegistryEvent(eventHandlers, event, data) {
|
|
|
816
816
|
});
|
|
817
817
|
}
|
|
818
818
|
|
|
819
|
+
// src/tools/registry-mutations.ts
|
|
820
|
+
function eraseToolType(tool) {
|
|
821
|
+
return tool;
|
|
822
|
+
}
|
|
823
|
+
function registerRegistryTool(tools, tool, emit, events) {
|
|
824
|
+
const name = tool.metadata.name;
|
|
825
|
+
if (tools.has(name)) {
|
|
826
|
+
throw new Error(
|
|
827
|
+
`Tool with name "${name}" is already registered. Use update() to modify it.`
|
|
828
|
+
);
|
|
829
|
+
}
|
|
830
|
+
tools.set(name, eraseToolType(tool));
|
|
831
|
+
emit(events.registered, tool);
|
|
832
|
+
}
|
|
833
|
+
function removeRegistryTool(tools, name, emit, events) {
|
|
834
|
+
const tool = tools.get(name);
|
|
835
|
+
if (!tool) {
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
tools.delete(name);
|
|
839
|
+
emit(events.removed, tool);
|
|
840
|
+
return true;
|
|
841
|
+
}
|
|
842
|
+
function updateRegistryTool(tools, name, tool, emit, events) {
|
|
843
|
+
if (!tools.has(name)) {
|
|
844
|
+
return false;
|
|
845
|
+
}
|
|
846
|
+
if (tool.metadata.name !== name) {
|
|
847
|
+
throw new Error(
|
|
848
|
+
`Cannot update tool: metadata.name "${tool.metadata.name}" does not match registry key "${name}". To rename a tool, remove it and register it again with the new name.`
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
tools.set(name, eraseToolType(tool));
|
|
852
|
+
emit(events.updated, { name, tool });
|
|
853
|
+
return true;
|
|
854
|
+
}
|
|
855
|
+
function registerManyRegistryTools(tools, toolsToRegister, emit, events) {
|
|
856
|
+
const pendingTools = Array.from(toolsToRegister);
|
|
857
|
+
const inputNames = /* @__PURE__ */ new Set();
|
|
858
|
+
const duplicatesInInput = [];
|
|
859
|
+
for (const tool of pendingTools) {
|
|
860
|
+
const name = tool.metadata.name;
|
|
861
|
+
if (inputNames.has(name)) {
|
|
862
|
+
duplicatesInInput.push(name);
|
|
863
|
+
} else {
|
|
864
|
+
inputNames.add(name);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
if (duplicatesInInput.length > 0) {
|
|
868
|
+
throw new Error(
|
|
869
|
+
`Cannot register tools: duplicate names in input list: ${duplicatesInInput.join(", ")}`
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
const conflicts = [];
|
|
873
|
+
for (const tool of pendingTools) {
|
|
874
|
+
if (tools.has(tool.metadata.name)) {
|
|
875
|
+
conflicts.push(tool.metadata.name);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (conflicts.length > 0) {
|
|
879
|
+
throw new Error(
|
|
880
|
+
`Cannot register tools: the following names already exist: ${conflicts.join(", ")}`
|
|
881
|
+
);
|
|
882
|
+
}
|
|
883
|
+
for (const tool of pendingTools) {
|
|
884
|
+
registerRegistryTool(tools, tool, emit, events);
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
function clearRegistryTools(tools, emit, events) {
|
|
888
|
+
tools.clear();
|
|
889
|
+
emit(events.cleared, null);
|
|
890
|
+
}
|
|
891
|
+
|
|
819
892
|
// src/tools/registry-prompt.ts
|
|
820
893
|
import { z as z3 } from "zod";
|
|
821
894
|
|
|
@@ -1086,33 +1159,31 @@ var RegistryEvent = /* @__PURE__ */ ((RegistryEvent2) => {
|
|
|
1086
1159
|
RegistryEvent2["REGISTRY_CLEARED"] = "registry:cleared";
|
|
1087
1160
|
return RegistryEvent2;
|
|
1088
1161
|
})(RegistryEvent || {});
|
|
1089
|
-
function eraseToolType(tool) {
|
|
1090
|
-
return tool;
|
|
1091
|
-
}
|
|
1092
1162
|
var ToolRegistry = class {
|
|
1093
1163
|
tools = /* @__PURE__ */ new Map();
|
|
1094
1164
|
eventHandlers = /* @__PURE__ */ new Map();
|
|
1165
|
+
mutationEvents = {
|
|
1166
|
+
registered: "tool:registered" /* TOOL_REGISTERED */,
|
|
1167
|
+
removed: "tool:removed" /* TOOL_REMOVED */,
|
|
1168
|
+
updated: "tool:updated" /* TOOL_UPDATED */,
|
|
1169
|
+
cleared: "registry:cleared" /* REGISTRY_CLEARED */
|
|
1170
|
+
};
|
|
1171
|
+
emitMutation = (event, data) => {
|
|
1172
|
+
this.emit(event, data);
|
|
1173
|
+
};
|
|
1095
1174
|
/**
|
|
1096
1175
|
* Register a tool in the registry
|
|
1097
1176
|
*
|
|
1098
1177
|
* @param tool - The tool to register
|
|
1099
1178
|
* @throws Error if a tool with the same name already exists
|
|
1100
1179
|
*
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1180
|
+
* @example
|
|
1181
|
+
* ```ts
|
|
1182
|
+
* registry.register(readFileTool);
|
|
1104
1183
|
* ```
|
|
1105
1184
|
*/
|
|
1106
1185
|
register(tool) {
|
|
1107
|
-
|
|
1108
|
-
const name = tool.metadata.name;
|
|
1109
|
-
if (this.tools.has(name)) {
|
|
1110
|
-
throw new Error(
|
|
1111
|
-
`Tool with name "${name}" is already registered. Use update() to modify it.`
|
|
1112
|
-
);
|
|
1113
|
-
}
|
|
1114
|
-
this.tools.set(name, erasedTool);
|
|
1115
|
-
this.emit("tool:registered" /* TOOL_REGISTERED */, tool);
|
|
1186
|
+
registerRegistryTool(this.tools, tool, this.emitMutation, this.mutationEvents);
|
|
1116
1187
|
}
|
|
1117
1188
|
/**
|
|
1118
1189
|
* Get a tool by name
|
|
@@ -1153,20 +1224,14 @@ var ToolRegistry = class {
|
|
|
1153
1224
|
* @param name - The tool name
|
|
1154
1225
|
* @returns True if the tool was removed, false if it didn't exist
|
|
1155
1226
|
*
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1227
|
+
* @example
|
|
1228
|
+
* ```ts
|
|
1229
|
+
* const removed = registry.remove('read-file');
|
|
1230
|
+
* console.log(removed ? 'Removed' : 'Not found');
|
|
1160
1231
|
* ```
|
|
1161
1232
|
*/
|
|
1162
1233
|
remove(name) {
|
|
1163
|
-
|
|
1164
|
-
if (!tool) {
|
|
1165
|
-
return false;
|
|
1166
|
-
}
|
|
1167
|
-
this.tools.delete(name);
|
|
1168
|
-
this.emit("tool:removed" /* TOOL_REMOVED */, tool);
|
|
1169
|
-
return true;
|
|
1234
|
+
return removeRegistryTool(this.tools, name, this.emitMutation, this.mutationEvents);
|
|
1170
1235
|
}
|
|
1171
1236
|
/**
|
|
1172
1237
|
* Update an existing tool
|
|
@@ -1176,24 +1241,13 @@ var ToolRegistry = class {
|
|
|
1176
1241
|
* @returns True if updated, false if the tool didn't exist
|
|
1177
1242
|
* @throws Error if the tool's metadata.name doesn't match the name parameter
|
|
1178
1243
|
*
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1244
|
+
* @example
|
|
1245
|
+
* ```ts
|
|
1246
|
+
* const updated = registry.update('read-file', newReadFileTool);
|
|
1182
1247
|
* ```
|
|
1183
1248
|
*/
|
|
1184
1249
|
update(name, tool) {
|
|
1185
|
-
|
|
1186
|
-
if (!this.tools.has(name)) {
|
|
1187
|
-
return false;
|
|
1188
|
-
}
|
|
1189
|
-
if (tool.metadata.name !== name) {
|
|
1190
|
-
throw new Error(
|
|
1191
|
-
`Cannot update tool: metadata.name "${tool.metadata.name}" does not match registry key "${name}". To rename a tool, remove it and register it again with the new name.`
|
|
1192
|
-
);
|
|
1193
|
-
}
|
|
1194
|
-
this.tools.set(name, erasedTool);
|
|
1195
|
-
this.emit("tool:updated" /* TOOL_UPDATED */, { name, tool });
|
|
1196
|
-
return true;
|
|
1250
|
+
return updateRegistryTool(this.tools, name, tool, this.emitMutation, this.mutationEvents);
|
|
1197
1251
|
}
|
|
1198
1252
|
/**
|
|
1199
1253
|
* Get all registered tools
|
|
@@ -1260,55 +1314,25 @@ var ToolRegistry = class {
|
|
|
1260
1314
|
* @param tools - Iterable of tools to register
|
|
1261
1315
|
* @throws Error if any tool name conflicts with existing tools
|
|
1262
1316
|
*
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1317
|
+
* @example
|
|
1318
|
+
* ```ts
|
|
1319
|
+
* registry.registerMany([tool1, tool2, tool3]);
|
|
1266
1320
|
* ```
|
|
1267
1321
|
*/
|
|
1268
1322
|
registerMany(tools) {
|
|
1269
|
-
|
|
1270
|
-
const inputNames = /* @__PURE__ */ new Set();
|
|
1271
|
-
const duplicatesInInput = [];
|
|
1272
|
-
for (const tool of toolsToRegister) {
|
|
1273
|
-
const name = tool.metadata.name;
|
|
1274
|
-
if (inputNames.has(name)) {
|
|
1275
|
-
duplicatesInInput.push(name);
|
|
1276
|
-
} else {
|
|
1277
|
-
inputNames.add(name);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
if (duplicatesInInput.length > 0) {
|
|
1281
|
-
throw new Error(
|
|
1282
|
-
`Cannot register tools: duplicate names in input list: ${duplicatesInInput.join(", ")}`
|
|
1283
|
-
);
|
|
1284
|
-
}
|
|
1285
|
-
const conflicts = [];
|
|
1286
|
-
for (const tool of toolsToRegister) {
|
|
1287
|
-
if (this.tools.has(tool.metadata.name)) {
|
|
1288
|
-
conflicts.push(tool.metadata.name);
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
if (conflicts.length > 0) {
|
|
1292
|
-
throw new Error(
|
|
1293
|
-
`Cannot register tools: the following names already exist: ${conflicts.join(", ")}`
|
|
1294
|
-
);
|
|
1295
|
-
}
|
|
1296
|
-
for (const tool of toolsToRegister) {
|
|
1297
|
-
this.register(tool);
|
|
1298
|
-
}
|
|
1323
|
+
registerManyRegistryTools(this.tools, tools, this.emitMutation, this.mutationEvents);
|
|
1299
1324
|
}
|
|
1300
1325
|
/**
|
|
1301
1326
|
* Clear all tools from the registry
|
|
1302
1327
|
*
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1328
|
+
* @example
|
|
1329
|
+
* ```ts
|
|
1330
|
+
* registry.clear();
|
|
1331
|
+
* console.log(registry.size()); // 0
|
|
1307
1332
|
* ```
|
|
1308
1333
|
*/
|
|
1309
1334
|
clear() {
|
|
1310
|
-
this.tools.
|
|
1311
|
-
this.emit("registry:cleared" /* REGISTRY_CLEARED */, null);
|
|
1335
|
+
clearRegistryTools(this.tools, this.emitMutation, this.mutationEvents);
|
|
1312
1336
|
}
|
|
1313
1337
|
/**
|
|
1314
1338
|
* Get the number of registered tools
|
|
@@ -1647,6 +1671,12 @@ var ManagedTool = class {
|
|
|
1647
1671
|
failedExecutions: 0
|
|
1648
1672
|
};
|
|
1649
1673
|
_healthCheckTimer;
|
|
1674
|
+
_beforeExitHandler;
|
|
1675
|
+
_healthCheckInFlight = false;
|
|
1676
|
+
_cleaningUp = false;
|
|
1677
|
+
_cleanupPromise;
|
|
1678
|
+
_initializePromise;
|
|
1679
|
+
_lifecycleGeneration = 0;
|
|
1650
1680
|
constructor(config) {
|
|
1651
1681
|
this.name = config.name;
|
|
1652
1682
|
this.description = config.description;
|
|
@@ -1657,17 +1687,7 @@ var ManagedTool = class {
|
|
|
1657
1687
|
this.autoCleanup = config.autoCleanup ?? true;
|
|
1658
1688
|
this.healthCheckInterval = config.healthCheckInterval;
|
|
1659
1689
|
this._context = config.context;
|
|
1660
|
-
|
|
1661
|
-
process.on("beforeExit", () => {
|
|
1662
|
-
this.cleanup().catch(
|
|
1663
|
-
(err) => logger3.error("Cleanup failed", {
|
|
1664
|
-
toolName: this.name,
|
|
1665
|
-
error: err instanceof Error ? err.message : String(err),
|
|
1666
|
-
...err instanceof Error && err.stack ? { stack: err.stack } : {}
|
|
1667
|
-
})
|
|
1668
|
-
);
|
|
1669
|
-
});
|
|
1670
|
-
}
|
|
1690
|
+
this.ensureBeforeExitHandler();
|
|
1671
1691
|
}
|
|
1672
1692
|
/**
|
|
1673
1693
|
* Get the tool context (e.g., connection pool, API client)
|
|
@@ -1691,28 +1711,26 @@ var ManagedTool = class {
|
|
|
1691
1711
|
* Initialize the tool
|
|
1692
1712
|
*/
|
|
1693
1713
|
async initialize() {
|
|
1694
|
-
if (this.
|
|
1714
|
+
if (this._initializePromise) {
|
|
1715
|
+
await this._initializePromise;
|
|
1695
1716
|
return;
|
|
1696
1717
|
}
|
|
1697
|
-
if (this.
|
|
1698
|
-
await this.
|
|
1718
|
+
if (this._cleanupPromise) {
|
|
1719
|
+
await this._cleanupPromise;
|
|
1720
|
+
if (this._initializePromise) {
|
|
1721
|
+
await this._initializePromise;
|
|
1722
|
+
return;
|
|
1723
|
+
}
|
|
1699
1724
|
}
|
|
1700
|
-
this._initialized
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
this._stats.lastHealthCheck = {
|
|
1710
|
-
healthy: false,
|
|
1711
|
-
error: error.message
|
|
1712
|
-
};
|
|
1713
|
-
this._stats.lastHealthCheckTime = Date.now();
|
|
1714
|
-
}
|
|
1715
|
-
}, 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;
|
|
1716
1734
|
}
|
|
1717
1735
|
}
|
|
1718
1736
|
/**
|
|
@@ -1739,24 +1757,55 @@ var ManagedTool = class {
|
|
|
1739
1757
|
* Cleanup the tool
|
|
1740
1758
|
*/
|
|
1741
1759
|
async cleanup() {
|
|
1742
|
-
if (
|
|
1760
|
+
if (this._cleanupPromise) {
|
|
1761
|
+
await this._cleanupPromise;
|
|
1743
1762
|
return;
|
|
1744
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;
|
|
1745
1780
|
if (this._healthCheckTimer) {
|
|
1746
1781
|
clearInterval(this._healthCheckTimer);
|
|
1747
1782
|
this._healthCheckTimer = void 0;
|
|
1748
1783
|
}
|
|
1749
|
-
if (this.
|
|
1750
|
-
|
|
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;
|
|
1751
1791
|
}
|
|
1752
1792
|
this._initialized = false;
|
|
1753
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;
|
|
1754
1803
|
}
|
|
1755
1804
|
/**
|
|
1756
1805
|
* Run health check
|
|
1757
1806
|
*/
|
|
1758
1807
|
async healthCheck() {
|
|
1759
|
-
if (!this._initialized) {
|
|
1808
|
+
if (!this._initialized || this._cleaningUp) {
|
|
1760
1809
|
return {
|
|
1761
1810
|
healthy: false,
|
|
1762
1811
|
error: "Tool is not initialized"
|
|
@@ -1768,15 +1817,28 @@ var ManagedTool = class {
|
|
|
1768
1817
|
metadata: { message: "No health check configured" }
|
|
1769
1818
|
};
|
|
1770
1819
|
}
|
|
1820
|
+
const lifecycleGeneration = this._lifecycleGeneration;
|
|
1771
1821
|
try {
|
|
1772
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
|
+
}
|
|
1773
1829
|
this._stats.lastHealthCheck = result;
|
|
1774
1830
|
this._stats.lastHealthCheckTime = Date.now();
|
|
1775
1831
|
return result;
|
|
1776
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
|
+
}
|
|
1777
1839
|
const result = {
|
|
1778
1840
|
healthy: false,
|
|
1779
|
-
error: error
|
|
1841
|
+
error: getErrorMessage(error)
|
|
1780
1842
|
};
|
|
1781
1843
|
this._stats.lastHealthCheck = result;
|
|
1782
1844
|
this._stats.lastHealthCheckTime = Date.now();
|
|
@@ -1810,10 +1872,68 @@ var ManagedTool = class {
|
|
|
1810
1872
|
}
|
|
1811
1873
|
};
|
|
1812
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
|
+
}
|
|
1813
1930
|
};
|
|
1814
1931
|
function createManagedTool(config) {
|
|
1815
1932
|
return new ManagedTool(config);
|
|
1816
1933
|
}
|
|
1934
|
+
function getErrorMessage(error) {
|
|
1935
|
+
return error instanceof Error ? error.message : String(error);
|
|
1936
|
+
}
|
|
1817
1937
|
|
|
1818
1938
|
// src/tools/composition.ts
|
|
1819
1939
|
function isConditionalStep(step) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentforge/core",
|
|
3
|
-
"version": "0.16.
|
|
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",
|