@agentforge/tools 0.18.4 → 0.18.5

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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { toolBuilder, ToolCategory, LogLevel, createLogger, createTool } from '@agentforge/core';
2
2
  import { lookup } from 'dns/promises';
3
3
  import net from 'net';
4
- import axios11 from 'axios';
4
+ import axios5 from 'axios';
5
5
  import { z } from 'zod';
6
6
  import * as cheerio from 'cheerio';
7
7
  import { WebClient } from '@slack/web-api';
@@ -201,7 +201,7 @@ async function requestWithDestinationPolicy(config, policy = {}) {
201
201
  for (let redirectCount = 0; ; redirectCount += 1) {
202
202
  const validatedAddresses = await validateDestinationAllowed(currentUrl, effectivePolicy);
203
203
  currentConfig.lookup = createPinnedLookup(validatedAddresses);
204
- const response = await axios11(currentConfig);
204
+ const response = await axios5(currentConfig);
205
205
  if (!isRedirectStatus(response.status)) return response;
206
206
  if (effectivePolicy.allowRedirects === false) blockDestination(currentUrl, "redirect");
207
207
  if (redirectCount >= maxRedirects) throw new DestinationPolicyError(currentUrl, "redirect", `Maximum redirect count (${maxRedirects}) exceeded for ${currentUrl}`);
@@ -712,7 +712,7 @@ var DuckDuckGoProvider = class {
712
712
  async search(query, maxResults, timeout = DEFAULT_TIMEOUT) {
713
713
  try {
714
714
  return await retryWithBackoff(async () => {
715
- const response = await axios11.get("https://api.duckduckgo.com/", {
715
+ const response = await axios5.get("https://api.duckduckgo.com/", {
716
716
  params: {
717
717
  q: query,
718
718
  format: "json"
@@ -813,7 +813,7 @@ var SerperProvider = class {
813
813
  }
814
814
  try {
815
815
  return await retryWithBackoff(async () => {
816
- const response = await axios11.post(
816
+ const response = await axios5.post(
817
817
  "https://google.serper.dev/search",
818
818
  {
819
819
  q: query,
@@ -1216,38 +1216,91 @@ function createGetConfiguredAuth(apiKey, email, siteUrl) {
1216
1216
  return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
1217
1217
  };
1218
1218
  }
1219
- function createGetConfiguredAuthHeader(getConfiguredAuth) {
1220
- return function getConfiguredAuthHeader() {
1221
- const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfiguredAuth();
1222
- const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1223
- return `Basic ${auth2}`;
1224
- };
1225
- }
1226
1219
  function getConfig() {
1227
1220
  const ATLASSIAN_API_KEY = process.env.ATLASSIAN_API_KEY || "";
1228
1221
  const ATLASSIAN_EMAIL = process.env.ATLASSIAN_EMAIL || "";
1229
1222
  const ATLASSIAN_SITE_URL = (process.env.ATLASSIAN_SITE_URL || "").replace(/\/$/, "");
1230
1223
  if (!ATLASSIAN_API_KEY || !ATLASSIAN_EMAIL || !ATLASSIAN_SITE_URL) {
1231
- throw new Error("Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env");
1224
+ throw new Error(
1225
+ "Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env"
1226
+ );
1232
1227
  }
1233
1228
  return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
1234
1229
  }
1235
- function getAuthHeader() {
1236
- const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfig();
1237
- const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1238
- return `Basic ${auth2}`;
1230
+ function isRecord(value) {
1231
+ return typeof value === "object" && value !== null;
1232
+ }
1233
+ function describeError(error) {
1234
+ const errorRecord = isRecord(error) ? error : void 0;
1235
+ const response = isRecord(errorRecord?.response) ? errorRecord.response : void 0;
1236
+ const responseData = isRecord(response?.data) ? response.data : void 0;
1237
+ const providerMessage = typeof responseData?.message === "string" ? responseData.message : void 0;
1238
+ const errorMessage = typeof errorRecord?.message === "string" ? errorRecord.message : void 0;
1239
+ return {
1240
+ message: providerMessage || errorMessage,
1241
+ status: typeof response?.status === "number" ? response.status : void 0
1242
+ };
1239
1243
  }
1240
- function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1241
- return toolBuilder().name("search-confluence").description("Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts.").category(ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes("Use this to find relevant documentation, policies, or information in Confluence. You can search by keywords or use CQL for advanced queries (e.g., 'space=AI AND type=page'). Use get-confluence-page to retrieve full content of specific pages.").suggests(["get-confluence-page"]).schema(z.object({
1242
- query: z.string().describe("Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"),
1243
- limit: z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1244
- })).implement(async ({ query, limit = 10 }) => {
1244
+ function authenticatedConfig(auth2, config = {}) {
1245
+ const credentials = Buffer.from(`${auth2.ATLASSIAN_EMAIL}:${auth2.ATLASSIAN_API_KEY}`).toString(
1246
+ "base64"
1247
+ );
1248
+ return {
1249
+ ...config,
1250
+ headers: {
1251
+ ...config.headers,
1252
+ Authorization: `Basic ${credentials}`
1253
+ }
1254
+ };
1255
+ }
1256
+ function createConfluenceRequest(getAuth) {
1257
+ return {
1258
+ async get(path13, config = {}) {
1259
+ const auth2 = getAuth();
1260
+ const response = await axios5.get(
1261
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1262
+ authenticatedConfig(auth2, config)
1263
+ );
1264
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1265
+ },
1266
+ async post(path13, data, config = {}) {
1267
+ const auth2 = getAuth();
1268
+ const response = await axios5.post(
1269
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1270
+ data,
1271
+ authenticatedConfig(auth2, config)
1272
+ );
1273
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1274
+ },
1275
+ async put(path13, data, config = {}) {
1276
+ const auth2 = getAuth();
1277
+ const response = await axios5.put(
1278
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1279
+ data,
1280
+ authenticatedConfig(auth2, config)
1281
+ );
1282
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1283
+ },
1284
+ describeError
1285
+ };
1286
+ }
1287
+ function createSearchConfluenceTool(request2, logger20) {
1288
+ return toolBuilder().name("search-confluence").description(
1289
+ "Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts."
1290
+ ).category(ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes(
1291
+ "Use this to find relevant documentation, policies, or information in Confluence. You can search by keywords or use CQL for advanced queries (e.g., 'space=AI AND type=page'). Use get-confluence-page to retrieve full content of specific pages."
1292
+ ).suggests(["get-confluence-page"]).schema(
1293
+ z.object({
1294
+ query: z.string().describe(
1295
+ "Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"
1296
+ ),
1297
+ limit: z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1298
+ })
1299
+ ).implement(async ({ query, limit = 10 }) => {
1245
1300
  logger20.info("search-confluence called", { query, limit });
1246
1301
  try {
1247
- const { ATLASSIAN_SITE_URL } = getAuth();
1248
- const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
1302
+ const response = await request2.get("/wiki/rest/api/content/search", {
1249
1303
  headers: {
1250
- Authorization: getAuthHeader2(),
1251
1304
  Accept: "application/json"
1252
1305
  },
1253
1306
  params: {
@@ -1256,22 +1309,24 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1256
1309
  expand: "space,version"
1257
1310
  }
1258
1311
  });
1259
- const { ATLASSIAN_SITE_URL: siteUrl } = getAuth();
1260
1312
  const results = response.data.results.map((page) => ({
1261
1313
  id: page.id,
1262
1314
  title: page.title,
1263
1315
  type: page.type,
1264
1316
  space: page.space?.name || "Unknown",
1265
1317
  spaceKey: page.space?.key || "",
1266
- url: `${siteUrl}/wiki${page._links.webui}`,
1318
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1267
1319
  lastModified: page.version?.when || ""
1268
1320
  }));
1269
1321
  if (results.length === 0) {
1270
- logger20.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
1271
- query,
1272
- limit,
1273
- totalSize: response.data.totalSize
1274
- });
1322
+ logger20.warn(
1323
+ "search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry",
1324
+ {
1325
+ query,
1326
+ limit,
1327
+ totalSize: response.data.totalSize
1328
+ }
1329
+ );
1275
1330
  } else {
1276
1331
  logger20.info("search-confluence result", {
1277
1332
  query,
@@ -1288,28 +1343,33 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1288
1343
  results
1289
1344
  });
1290
1345
  } catch (error) {
1346
+ const description = request2.describeError(error);
1291
1347
  logger20.error("search-confluence error", {
1292
1348
  query,
1293
- error: error.response?.data?.message || error.message,
1294
- status: error.response?.status
1349
+ ...description.message !== void 0 ? { error: description.message } : {},
1350
+ ...description.status !== void 0 ? { status: description.status } : {}
1295
1351
  });
1296
1352
  return JSON.stringify({
1297
1353
  success: false,
1298
- error: error.response?.data?.message || error.message
1354
+ error: description.message
1299
1355
  });
1300
1356
  }
1301
1357
  }).build();
1302
1358
  }
1303
- function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1304
- return toolBuilder().name("get-confluence-page").description("Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata.").category(ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes("Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results.").requires(["search-confluence"]).schema(z.object({
1305
- page_id: z.string().describe("The Confluence page ID (from search results)")
1306
- })).implement(async ({ page_id }) => {
1359
+ function createGetConfluencePageTool(request2, logger20) {
1360
+ return toolBuilder().name("get-confluence-page").description(
1361
+ "Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata."
1362
+ ).category(ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes(
1363
+ "Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results."
1364
+ ).requires(["search-confluence"]).schema(
1365
+ z.object({
1366
+ page_id: z.string().describe("The Confluence page ID (from search results)")
1367
+ })
1368
+ ).implement(async ({ page_id }) => {
1307
1369
  logger20.info("get-confluence-page called", { page_id });
1308
1370
  try {
1309
- const { ATLASSIAN_SITE_URL } = getAuth();
1310
- const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
1371
+ const response = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1311
1372
  headers: {
1312
- Authorization: getAuthHeader2(),
1313
1373
  Accept: "application/json"
1314
1374
  },
1315
1375
  params: {
@@ -1332,35 +1392,40 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1332
1392
  space: page.space?.name || "Unknown",
1333
1393
  spaceKey: page.space?.key || "",
1334
1394
  content: page.body?.storage?.value || "",
1335
- url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
1395
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1336
1396
  created: page.history?.createdDate || "",
1337
1397
  lastModified: page.version?.when || "",
1338
1398
  version: page.version?.number || 1
1339
1399
  }
1340
1400
  });
1341
1401
  } catch (error) {
1402
+ const description = request2.describeError(error);
1342
1403
  logger20.error("get-confluence-page error", {
1343
1404
  page_id,
1344
- error: error.response?.data?.message || error.message,
1345
- status: error.response?.status
1405
+ ...description.message !== void 0 ? { error: description.message } : {},
1406
+ ...description.status !== void 0 ? { status: description.status } : {}
1346
1407
  });
1347
1408
  return JSON.stringify({
1348
1409
  success: false,
1349
- error: error.response?.data?.message || error.message
1410
+ error: description.message
1350
1411
  });
1351
1412
  }
1352
1413
  }).build();
1353
1414
  }
1354
- function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1355
- return toolBuilder().name("list-confluence-spaces").description("List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information.").category(ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes("Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance').").follows(["search-confluence"]).schema(z.object({
1356
- limit: z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1357
- })).implement(async ({ limit = 25 }) => {
1415
+ function createListConfluenceSpacesTool(request2, logger20) {
1416
+ return toolBuilder().name("list-confluence-spaces").description(
1417
+ "List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information."
1418
+ ).category(ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes(
1419
+ "Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance')."
1420
+ ).follows(["search-confluence"]).schema(
1421
+ z.object({
1422
+ limit: z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1423
+ })
1424
+ ).implement(async ({ limit = 25 }) => {
1358
1425
  logger20.info("list-confluence-spaces called", { limit });
1359
1426
  try {
1360
- const { ATLASSIAN_SITE_URL } = getAuth();
1361
- const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
1427
+ const response = await request2.get("/wiki/rest/api/space", {
1362
1428
  headers: {
1363
- Authorization: getAuthHeader2(),
1364
1429
  Accept: "application/json"
1365
1430
  },
1366
1431
  params: {
@@ -1372,7 +1437,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1372
1437
  name: space.name,
1373
1438
  type: space.type,
1374
1439
  description: space.description?.plain?.value || "",
1375
- url: `${ATLASSIAN_SITE_URL}/wiki${space._links.webui}`
1440
+ url: `${response.siteUrl}/wiki${space._links.webui}`
1376
1441
  }));
1377
1442
  logger20.info("list-confluence-spaces result", {
1378
1443
  spaceCount: spaces.length,
@@ -1385,28 +1450,33 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1385
1450
  spaces
1386
1451
  });
1387
1452
  } catch (error) {
1453
+ const description = request2.describeError(error);
1388
1454
  logger20.error("list-confluence-spaces error", {
1389
- error: error.response?.data?.message || error.message,
1390
- status: error.response?.status
1455
+ ...description.message !== void 0 ? { error: description.message } : {},
1456
+ ...description.status !== void 0 ? { status: description.status } : {}
1391
1457
  });
1392
1458
  return JSON.stringify({
1393
1459
  success: false,
1394
- error: error.response?.data?.message || error.message
1460
+ error: description.message
1395
1461
  });
1396
1462
  }
1397
1463
  }).build();
1398
1464
  }
1399
- function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1400
- return toolBuilder().name("get-space-pages").description("Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area.").category(ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes("Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first.").requires(["list-confluence-spaces"]).schema(z.object({
1401
- space_key: z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1402
- limit: z.number().optional().describe("Maximum number of pages to return (default: 25)")
1403
- })).implement(async ({ space_key, limit = 25 }) => {
1465
+ function createGetSpacePagesTool(request2, logger20) {
1466
+ return toolBuilder().name("get-space-pages").description(
1467
+ "Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area."
1468
+ ).category(ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes(
1469
+ "Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first."
1470
+ ).requires(["list-confluence-spaces"]).schema(
1471
+ z.object({
1472
+ space_key: z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1473
+ limit: z.number().optional().describe("Maximum number of pages to return (default: 25)")
1474
+ })
1475
+ ).implement(async ({ space_key, limit = 25 }) => {
1404
1476
  logger20.info("get-space-pages called", { space_key, limit });
1405
1477
  try {
1406
- const { ATLASSIAN_SITE_URL } = getAuth();
1407
- const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
1478
+ const response = await request2.get("/wiki/rest/api/content", {
1408
1479
  headers: {
1409
- Authorization: getAuthHeader2(),
1410
1480
  Accept: "application/json"
1411
1481
  },
1412
1482
  params: {
@@ -1419,14 +1489,17 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1419
1489
  const pages = response.data.results.map((page) => ({
1420
1490
  id: page.id,
1421
1491
  title: page.title,
1422
- url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
1492
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1423
1493
  lastModified: page.version?.when || ""
1424
1494
  }));
1425
1495
  if (pages.length === 0) {
1426
- logger20.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
1427
- space_key,
1428
- limit
1429
- });
1496
+ logger20.warn(
1497
+ "get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry",
1498
+ {
1499
+ space_key,
1500
+ limit
1501
+ }
1502
+ );
1430
1503
  } else {
1431
1504
  logger20.info("get-space-pages result", {
1432
1505
  space_key,
@@ -1442,28 +1515,38 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1442
1515
  pages
1443
1516
  });
1444
1517
  } catch (error) {
1518
+ const description = request2.describeError(error);
1445
1519
  logger20.error("get-space-pages error", {
1446
1520
  space_key,
1447
- error: error.response?.data?.message || error.message,
1448
- status: error.response?.status
1521
+ ...description.message !== void 0 ? { error: description.message } : {},
1522
+ ...description.status !== void 0 ? { status: description.status } : {}
1449
1523
  });
1450
1524
  return JSON.stringify({
1451
1525
  success: false,
1452
- error: error.response?.data?.message || error.message
1526
+ error: description.message
1453
1527
  });
1454
1528
  }
1455
1529
  }).build();
1456
1530
  }
1457
- function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1458
- return toolBuilder().name("create-confluence-page").description("Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format).").category(ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes("Use this to create new documentation pages. Content should be in Confluence storage format (HTML). Get the space key from list-confluence-spaces first. Be mindful of creating duplicate pages.").requires(["list-confluence-spaces"]).schema(z.object({
1459
- space_key: z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1460
- title: z.string().describe("The title of the new page"),
1461
- content: z.string().describe("The page content in HTML format (Confluence storage format)"),
1462
- parent_page_id: z.string().optional().describe("Optional parent page ID to create this as a child page")
1463
- })).implement(async ({ space_key, title, content, parent_page_id }) => {
1464
- logger20.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
1531
+ function createCreateConfluencePageTool(request2, logger20) {
1532
+ return toolBuilder().name("create-confluence-page").description(
1533
+ "Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format)."
1534
+ ).category(ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes(
1535
+ "Use this to create new documentation pages. Content should be in Confluence storage format (HTML). Get the space key from list-confluence-spaces first. Be mindful of creating duplicate pages."
1536
+ ).requires(["list-confluence-spaces"]).schema(
1537
+ z.object({
1538
+ space_key: z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1539
+ title: z.string().describe("The title of the new page"),
1540
+ content: z.string().describe("The page content in HTML format (Confluence storage format)"),
1541
+ parent_page_id: z.string().optional().describe("Optional parent page ID to create this as a child page")
1542
+ })
1543
+ ).implement(async ({ space_key, title, content, parent_page_id }) => {
1544
+ logger20.info("create-confluence-page called", {
1545
+ space_key,
1546
+ title,
1547
+ hasParent: !!parent_page_id
1548
+ });
1465
1549
  try {
1466
- const { ATLASSIAN_SITE_URL } = getAuth();
1467
1550
  const pageData = {
1468
1551
  type: "page",
1469
1552
  title,
@@ -1478,16 +1561,11 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1478
1561
  if (parent_page_id) {
1479
1562
  pageData.ancestors = [{ id: parent_page_id }];
1480
1563
  }
1481
- const response = await axios11.post(
1482
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content`,
1483
- pageData,
1484
- {
1485
- headers: {
1486
- Authorization: getAuthHeader2(),
1487
- "Content-Type": "application/json"
1488
- }
1564
+ const response = await request2.post("/wiki/rest/api/content", pageData, {
1565
+ headers: {
1566
+ "Content-Type": "application/json"
1489
1567
  }
1490
- );
1568
+ });
1491
1569
  logger20.info("create-confluence-page result", {
1492
1570
  page_id: response.data.id,
1493
1571
  title: response.data.title,
@@ -1499,45 +1577,45 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1499
1577
  id: response.data.id,
1500
1578
  title: response.data.title,
1501
1579
  space: space_key,
1502
- url: `${ATLASSIAN_SITE_URL}/wiki${response.data._links.webui}`,
1580
+ url: `${response.siteUrl}/wiki${response.data._links.webui}`,
1503
1581
  version: response.data.version?.number || 1
1504
1582
  }
1505
1583
  });
1506
1584
  } catch (error) {
1585
+ const description = request2.describeError(error);
1507
1586
  logger20.error("create-confluence-page error", {
1508
1587
  space_key,
1509
1588
  title,
1510
- error: error.response?.data?.message || error.message,
1511
- status: error.response?.status
1589
+ ...description.message !== void 0 ? { error: description.message } : {},
1590
+ ...description.status !== void 0 ? { status: description.status } : {}
1512
1591
  });
1513
1592
  return JSON.stringify({
1514
1593
  success: false,
1515
- error: error.response?.data?.message || error.message
1594
+ error: description.message
1516
1595
  });
1517
1596
  }
1518
1597
  }).build();
1519
1598
  }
1520
- function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1521
- return toolBuilder().name("update-confluence-page").description("Update an existing Confluence page's content. Requires page ID, new title, and new content.").category(ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes("Use this to update existing documentation. You must provide the page ID (from search results). The tool will automatically handle version incrementing. Always get the current page content first to avoid overwriting important information.").requires(["get-confluence-page"]).schema(z.object({
1522
- page_id: z.string().describe("The ID of the page to update"),
1523
- title: z.string().describe("The new title for the page"),
1524
- content: z.string().describe("The new content in HTML format (Confluence storage format)")
1525
- })).implement(async ({ page_id, title, content }) => {
1599
+ function createUpdateConfluencePageTool(request2, logger20) {
1600
+ return toolBuilder().name("update-confluence-page").description(
1601
+ "Update an existing Confluence page's content. Requires page ID, new title, and new content."
1602
+ ).category(ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes(
1603
+ "Use this to update existing documentation. You must provide the page ID (from search results). The tool will automatically handle version incrementing. Always get the current page content first to avoid overwriting important information."
1604
+ ).requires(["get-confluence-page"]).schema(
1605
+ z.object({
1606
+ page_id: z.string().describe("The ID of the page to update"),
1607
+ title: z.string().describe("The new title for the page"),
1608
+ content: z.string().describe("The new content in HTML format (Confluence storage format)")
1609
+ })
1610
+ ).implement(async ({ page_id, title, content }) => {
1526
1611
  logger20.info("update-confluence-page called", { page_id, title });
1527
1612
  try {
1528
- const { ATLASSIAN_SITE_URL } = getAuth();
1529
- const getResponse = await axios11.get(
1530
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1531
- {
1532
- headers: {
1533
- Authorization: getAuthHeader2()
1534
- },
1535
- params: { expand: "version" }
1536
- }
1537
- );
1613
+ const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1614
+ params: { expand: "version" }
1615
+ });
1538
1616
  const currentVersion = getResponse.data.version.number;
1539
- const updateResponse = await axios11.put(
1540
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1617
+ const updateResponse = await request2.put(
1618
+ `/wiki/rest/api/content/${page_id}`,
1541
1619
  {
1542
1620
  type: "page",
1543
1621
  title,
@@ -1551,7 +1629,6 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1551
1629
  },
1552
1630
  {
1553
1631
  headers: {
1554
- Authorization: getAuthHeader2(),
1555
1632
  "Content-Type": "application/json"
1556
1633
  }
1557
1634
  }
@@ -1567,49 +1644,49 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1567
1644
  page: {
1568
1645
  id: updateResponse.data.id,
1569
1646
  title: updateResponse.data.title,
1570
- url: `${ATLASSIAN_SITE_URL}/wiki${updateResponse.data._links.webui}`,
1647
+ url: `${updateResponse.siteUrl}/wiki${updateResponse.data._links.webui}`,
1571
1648
  version: updateResponse.data.version.number,
1572
1649
  previousVersion: currentVersion
1573
1650
  }
1574
1651
  });
1575
1652
  } catch (error) {
1653
+ const description = request2.describeError(error);
1576
1654
  logger20.error("update-confluence-page error", {
1577
1655
  page_id,
1578
1656
  title,
1579
- error: error.response?.data?.message || error.message,
1580
- status: error.response?.status
1657
+ ...description.message !== void 0 ? { error: description.message } : {},
1658
+ ...description.status !== void 0 ? { status: description.status } : {}
1581
1659
  });
1582
1660
  return JSON.stringify({
1583
1661
  success: false,
1584
- error: error.response?.data?.message || error.message
1662
+ error: description.message
1585
1663
  });
1586
1664
  }
1587
1665
  }).build();
1588
1666
  }
1589
- function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1590
- return toolBuilder().name("archive-confluence-page").description("Archive a Confluence page by moving it to trash. The page can be restored by space admins. Note: UI may require a note explaining why the page was archived.").category(ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes("Use this to archive outdated or obsolete documentation. The page is moved to trash, not permanently deleted. Space admins can restore it if needed. Be very careful - only archive pages that are truly obsolete.").conflicts(["create-confluence-page"]).schema(z.object({
1591
- page_id: z.string().describe("The ID of the page to archive"),
1592
- reason: z.string().optional().describe("Optional reason for archiving (for audit trail)")
1593
- })).implement(async ({ page_id, reason }) => {
1667
+ function createArchiveConfluencePageTool(request2, logger20) {
1668
+ return toolBuilder().name("archive-confluence-page").description(
1669
+ "Archive a Confluence page by moving it to trash. The page can be restored by space admins. Note: UI may require a note explaining why the page was archived."
1670
+ ).category(ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes(
1671
+ "Use this to archive outdated or obsolete documentation. The page is moved to trash, not permanently deleted. Space admins can restore it if needed. Be very careful - only archive pages that are truly obsolete."
1672
+ ).conflicts(["create-confluence-page"]).schema(
1673
+ z.object({
1674
+ page_id: z.string().describe("The ID of the page to archive"),
1675
+ reason: z.string().optional().describe("Optional reason for archiving (for audit trail)")
1676
+ })
1677
+ ).implement(async ({ page_id, reason }) => {
1594
1678
  logger20.info("archive-confluence-page called", {
1595
1679
  page_id,
1596
1680
  ...reason ? { reason } : {}
1597
1681
  });
1598
1682
  try {
1599
- const { ATLASSIAN_SITE_URL } = getAuth();
1600
- const getResponse = await axios11.get(
1601
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1602
- {
1603
- headers: {
1604
- Authorization: getAuthHeader2()
1605
- },
1606
- params: { expand: "version,body.storage,space" }
1607
- }
1608
- );
1683
+ const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1684
+ params: { expand: "version,body.storage,space" }
1685
+ });
1609
1686
  const currentVersion = getResponse.data.version.number;
1610
1687
  const pageData = getResponse.data;
1611
- await axios11.put(
1612
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1688
+ await request2.put(
1689
+ `/wiki/rest/api/content/${page_id}`,
1613
1690
  {
1614
1691
  version: { number: currentVersion + 1 },
1615
1692
  title: pageData.title,
@@ -1620,7 +1697,6 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1620
1697
  },
1621
1698
  {
1622
1699
  headers: {
1623
- Authorization: getAuthHeader2(),
1624
1700
  "Content-Type": "application/json"
1625
1701
  }
1626
1702
  }
@@ -1643,14 +1719,15 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1643
1719
  }
1644
1720
  });
1645
1721
  } catch (error) {
1722
+ const description = request2.describeError(error);
1646
1723
  logger20.error("archive-confluence-page error", {
1647
1724
  page_id,
1648
- error: error.response?.data?.message || error.message,
1649
- status: error.response?.status
1725
+ ...description.message !== void 0 ? { error: description.message } : {},
1726
+ ...description.status !== void 0 ? { status: description.status } : {}
1650
1727
  });
1651
1728
  return JSON.stringify({
1652
1729
  success: false,
1653
- error: error.response?.data?.message || error.message
1730
+ error: description.message
1654
1731
  });
1655
1732
  }
1656
1733
  }).build();
@@ -1659,13 +1736,14 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1659
1736
  // src/web/confluence/index.ts
1660
1737
  var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
1661
1738
  var logger2 = createLogger("[tools:confluence]", { level: logLevel2 });
1662
- var searchConfluence = createSearchConfluenceTool(getConfig, getAuthHeader, logger2);
1663
- var getConfluencePage = createGetConfluencePageTool(getConfig, getAuthHeader, logger2);
1664
- var listConfluenceSpaces = createListConfluenceSpacesTool(getConfig, getAuthHeader, logger2);
1665
- var getSpacePages = createGetSpacePagesTool(getConfig, getAuthHeader, logger2);
1666
- var createConfluencePage = createCreateConfluencePageTool(getConfig, getAuthHeader, logger2);
1667
- var updateConfluencePage = createUpdateConfluencePageTool(getConfig, getAuthHeader, logger2);
1668
- var archiveConfluencePage = createArchiveConfluencePageTool(getConfig, getAuthHeader, logger2);
1739
+ var request = createConfluenceRequest(getConfig);
1740
+ var searchConfluence = createSearchConfluenceTool(request, logger2);
1741
+ var getConfluencePage = createGetConfluencePageTool(request, logger2);
1742
+ var listConfluenceSpaces = createListConfluenceSpacesTool(request, logger2);
1743
+ var getSpacePages = createGetSpacePagesTool(request, logger2);
1744
+ var createConfluencePage = createCreateConfluencePageTool(request, logger2);
1745
+ var updateConfluencePage = createUpdateConfluencePageTool(request, logger2);
1746
+ var archiveConfluencePage = createArchiveConfluencePageTool(request, logger2);
1669
1747
  var confluenceTools = [
1670
1748
  // Read tools
1671
1749
  searchConfluence,
@@ -1678,22 +1756,17 @@ var confluenceTools = [
1678
1756
  archiveConfluencePage
1679
1757
  ];
1680
1758
  function createConfluenceTools(config = {}) {
1681
- const {
1682
- apiKey,
1683
- email,
1684
- siteUrl,
1685
- logLevel: customLogLevel
1686
- } = config;
1759
+ const { apiKey, email, siteUrl, logLevel: customLogLevel } = config;
1687
1760
  const getConfiguredAuth = createGetConfiguredAuth(apiKey, email, siteUrl);
1688
- const getConfiguredAuthHeader = createGetConfiguredAuthHeader(getConfiguredAuth);
1761
+ const request2 = createConfluenceRequest(getConfiguredAuth);
1689
1762
  const toolLogger = customLogLevel ? createLogger("tools:confluence", { level: customLogLevel }) : logger2;
1690
- const searchConfluence2 = createSearchConfluenceTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1691
- const getConfluencePage2 = createGetConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1692
- const listConfluenceSpaces2 = createListConfluenceSpacesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1693
- const getSpacePages2 = createGetSpacePagesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1694
- const createConfluencePage2 = createCreateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1695
- const updateConfluencePage2 = createUpdateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1696
- const archiveConfluencePage2 = createArchiveConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1763
+ const searchConfluence2 = createSearchConfluenceTool(request2, toolLogger);
1764
+ const getConfluencePage2 = createGetConfluencePageTool(request2, toolLogger);
1765
+ const listConfluenceSpaces2 = createListConfluenceSpacesTool(request2, toolLogger);
1766
+ const getSpacePages2 = createGetSpacePagesTool(request2, toolLogger);
1767
+ const createConfluencePage2 = createCreateConfluencePageTool(request2, toolLogger);
1768
+ const updateConfluencePage2 = createUpdateConfluencePageTool(request2, toolLogger);
1769
+ const archiveConfluencePage2 = createArchiveConfluencePageTool(request2, toolLogger);
1697
1770
  return {
1698
1771
  searchConfluence: searchConfluence2,
1699
1772
  getConfluencePage: getConfluencePage2,
@@ -1884,14 +1957,14 @@ function createJsonStringifyTool(defaultIndent = 2, defaultPretty = false) {
1884
1957
  };
1885
1958
  }).build();
1886
1959
  }
1887
- function isRecord(value) {
1960
+ function isRecord2(value) {
1888
1961
  return typeof value === "object" && value !== null && !Array.isArray(value);
1889
1962
  }
1890
1963
  function getPathValue(current, part) {
1891
1964
  const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1892
1965
  if (arrayMatch) {
1893
1966
  const [, key, index] = arrayMatch;
1894
- if (!isRecord(current)) {
1967
+ if (!isRecord2(current)) {
1895
1968
  return void 0;
1896
1969
  }
1897
1970
  const candidate = current[key];
@@ -1900,7 +1973,7 @@ function getPathValue(current, part) {
1900
1973
  }
1901
1974
  return candidate[parseInt(index, 10)];
1902
1975
  }
1903
- if (!isRecord(current)) {
1976
+ if (!isRecord2(current)) {
1904
1977
  return void 0;
1905
1978
  }
1906
1979
  return current[part];
@@ -2556,7 +2629,7 @@ async function initializeFromEnv() {
2556
2629
  // src/data/neo4j/embeddings/utils.ts
2557
2630
  function withProviderErrorMetadata(error, message) {
2558
2631
  const wrappedError = new Error(message);
2559
- if (!isRecord2(error)) return wrappedError;
2632
+ if (!isRecord3(error)) return wrappedError;
2560
2633
  if (typeof error.code === "string") wrappedError.code = error.code;
2561
2634
  if (error.response !== void 0) wrappedError.response = error.response;
2562
2635
  return wrappedError;
@@ -2569,12 +2642,12 @@ var DEFAULT_RETRY_CONFIG2 = {
2569
2642
  // 10 seconds
2570
2643
  backoffMultiplier: 2
2571
2644
  };
2572
- function isRecord2(value) {
2645
+ function isRecord3(value) {
2573
2646
  return typeof value === "object" && value !== null;
2574
2647
  }
2575
2648
  function isRetryableError2(error) {
2576
- if (!isRecord2(error)) return false;
2577
- const response = isRecord2(error.response) ? error.response : void 0;
2649
+ if (!isRecord3(error)) return false;
2650
+ const response = isRecord3(error.response) ? error.response : void 0;
2578
2651
  const status = typeof response?.status === "number" ? response.status : void 0;
2579
2652
  const code = typeof error.code === "string" ? error.code : void 0;
2580
2653
  const message = typeof error.message === "string" ? error.message : void 0;
@@ -2700,7 +2773,7 @@ var OpenAIEmbeddingProvider = class {
2700
2773
  const modelToUse = model || this.defaultModel;
2701
2774
  return retryWithBackoff2(async () => {
2702
2775
  try {
2703
- const response = await axios11.post(
2776
+ const response = await axios5.post(
2704
2777
  `${this.baseURL}/embeddings`,
2705
2778
  {
2706
2779
  input: text,
@@ -2730,7 +2803,7 @@ var OpenAIEmbeddingProvider = class {
2730
2803
  };
2731
2804
  } catch (error) {
2732
2805
  let message;
2733
- const response = axios11.isAxiosError(error) ? error.response : void 0;
2806
+ const response = axios5.isAxiosError(error) ? error.response : void 0;
2734
2807
  if (response?.status === 401) {
2735
2808
  message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
2736
2809
  } else if (response?.status === 429) {
@@ -2757,7 +2830,7 @@ var OpenAIEmbeddingProvider = class {
2757
2830
  const modelToUse = model || this.defaultModel;
2758
2831
  return retryWithBackoff2(async () => {
2759
2832
  try {
2760
- const response = await axios11.post(
2833
+ const response = await axios5.post(
2761
2834
  `${this.baseURL}/embeddings`,
2762
2835
  {
2763
2836
  input: texts,
@@ -2788,7 +2861,7 @@ var OpenAIEmbeddingProvider = class {
2788
2861
  };
2789
2862
  } catch (error) {
2790
2863
  let message;
2791
- const response = axios11.isAxiosError(error) ? error.response : void 0;
2864
+ const response = axios5.isAxiosError(error) ? error.response : void 0;
2792
2865
  if (response?.status === 401) {
2793
2866
  message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
2794
2867
  } else if (response?.status === 429) {
@@ -2830,7 +2903,7 @@ var CohereEmbeddingProvider = class {
2830
2903
  const modelToUse = model || this.defaultModel;
2831
2904
  return retryWithBackoff2(async () => {
2832
2905
  try {
2833
- const response = await axios11.post(
2906
+ const response = await axios5.post(
2834
2907
  `${this.baseUrl}/embed`,
2835
2908
  {
2836
2909
  texts,
@@ -2858,7 +2931,7 @@ var CohereEmbeddingProvider = class {
2858
2931
  } : void 0
2859
2932
  };
2860
2933
  } catch (error) {
2861
- if (axios11.isAxiosError(error)) {
2934
+ if (axios5.isAxiosError(error)) {
2862
2935
  const status = error.response?.status;
2863
2936
  const providerMessage = error.response?.data?.message || error.message;
2864
2937
  let message;
@@ -2896,7 +2969,7 @@ var HuggingFaceEmbeddingProvider = class {
2896
2969
  const modelToUse = model || this.defaultModel;
2897
2970
  return retryWithBackoff2(async () => {
2898
2971
  try {
2899
- const response = await axios11.post(
2972
+ const response = await axios5.post(
2900
2973
  `${this.baseUrl}/${modelToUse}`,
2901
2974
  {
2902
2975
  inputs: text,
@@ -2918,7 +2991,7 @@ var HuggingFaceEmbeddingProvider = class {
2918
2991
  dimensions: embedding.length
2919
2992
  };
2920
2993
  } catch (error) {
2921
- if (axios11.isAxiosError(error)) {
2994
+ if (axios5.isAxiosError(error)) {
2922
2995
  const status = error.response?.status;
2923
2996
  const message = error.response?.data?.error || error.message;
2924
2997
  let messageText;
@@ -2943,7 +3016,7 @@ var HuggingFaceEmbeddingProvider = class {
2943
3016
  const modelToUse = model || this.defaultModel;
2944
3017
  return retryWithBackoff2(async () => {
2945
3018
  try {
2946
- const response = await axios11.post(
3019
+ const response = await axios5.post(
2947
3020
  `${this.baseUrl}/${modelToUse}`,
2948
3021
  {
2949
3022
  inputs: texts,
@@ -2966,7 +3039,7 @@ var HuggingFaceEmbeddingProvider = class {
2966
3039
  dimensions
2967
3040
  };
2968
3041
  } catch (error) {
2969
- if (axios11.isAxiosError(error)) {
3042
+ if (axios5.isAxiosError(error)) {
2970
3043
  const status = error.response?.status;
2971
3044
  const message = error.response?.data?.error || error.message;
2972
3045
  let messageText;
@@ -3015,7 +3088,7 @@ var VoyageEmbeddingProvider = class {
3015
3088
  const modelToUse = model || this.defaultModel;
3016
3089
  return retryWithBackoff2(async () => {
3017
3090
  try {
3018
- const response = await axios11.post(
3091
+ const response = await axios5.post(
3019
3092
  `${this.baseUrl}/embeddings`,
3020
3093
  {
3021
3094
  input: texts,
@@ -3042,7 +3115,7 @@ var VoyageEmbeddingProvider = class {
3042
3115
  } : void 0
3043
3116
  };
3044
3117
  } catch (error) {
3045
- if (axios11.isAxiosError(error)) {
3118
+ if (axios5.isAxiosError(error)) {
3046
3119
  const status = error.response?.status;
3047
3120
  const message = error.response?.data?.message || error.message;
3048
3121
  let messageText;
@@ -3079,7 +3152,7 @@ var OllamaEmbeddingProvider = class {
3079
3152
  const modelToUse = model || this.defaultModel;
3080
3153
  return retryWithBackoff2(async () => {
3081
3154
  try {
3082
- const response = await axios11.post(
3155
+ const response = await axios5.post(
3083
3156
  `${this.baseUrl}/api/embeddings`,
3084
3157
  {
3085
3158
  model: modelToUse,
@@ -3098,7 +3171,7 @@ var OllamaEmbeddingProvider = class {
3098
3171
  dimensions: embedding.length
3099
3172
  };
3100
3173
  } catch (error) {
3101
- if (axios11.isAxiosError(error)) {
3174
+ if (axios5.isAxiosError(error)) {
3102
3175
  const status = error.response?.status;
3103
3176
  const message = error.response?.data?.error || error.message;
3104
3177
  let messageText;
@@ -3491,6 +3564,16 @@ function formatResults(records) {
3491
3564
  });
3492
3565
  }
3493
3566
 
3567
+ // src/data/neo4j/tools/session-owner.ts
3568
+ async function withNeo4jSession(database, operation) {
3569
+ const session = neo4jPool.getSession(database);
3570
+ try {
3571
+ return await operation(session);
3572
+ } finally {
3573
+ await session.close();
3574
+ }
3575
+ }
3576
+
3494
3577
  // src/data/neo4j/tools/neo4j-query.ts
3495
3578
  var logger4 = createLogger("agentforge:tools:neo4j:query");
3496
3579
  function createNeo4jQueryTool() {
@@ -3511,8 +3594,7 @@ function createNeo4jQueryTool() {
3511
3594
  ...input.database ? { database: input.database } : {}
3512
3595
  });
3513
3596
  try {
3514
- const session = neo4jPool.getSession(input.database);
3515
- try {
3597
+ return await withNeo4jSession(input.database, async (session) => {
3516
3598
  const result = await session.run(input.cypher, input.parameters || {});
3517
3599
  const formattedResults = formatResults(result.records);
3518
3600
  const duration = Date.now() - startTime;
@@ -3541,9 +3623,7 @@ function createNeo4jQueryTool() {
3541
3623
  }
3542
3624
  }
3543
3625
  };
3544
- } finally {
3545
- await session.close();
3546
- }
3626
+ });
3547
3627
  } catch (error) {
3548
3628
  const duration = Date.now() - startTime;
3549
3629
  const errorMessage = error instanceof Error ? error.message : "Failed to execute query";
@@ -3571,8 +3651,7 @@ function createNeo4jGetSchemaTool() {
3571
3651
  };
3572
3652
  }
3573
3653
  try {
3574
- const session = neo4jPool.getSession(input.database);
3575
- try {
3654
+ return await withNeo4jSession(input.database, async (session) => {
3576
3655
  const labelsResult = await session.run("CALL db.labels()");
3577
3656
  const nodeLabels = labelsResult.records.map((r) => r.get("label"));
3578
3657
  const relTypesResult = await session.run("CALL db.relationshipTypes()");
@@ -3612,9 +3691,7 @@ function createNeo4jGetSchemaTool() {
3612
3691
  totalIndexes: indexes.length
3613
3692
  }
3614
3693
  };
3615
- } finally {
3616
- await session.close();
3617
- }
3694
+ });
3618
3695
  } catch (error) {
3619
3696
  return {
3620
3697
  success: false,
@@ -3693,8 +3770,7 @@ function createNeo4jFindNodesTool() {
3693
3770
  }
3694
3771
  try {
3695
3772
  const safeLabel = validateLabel(input.label);
3696
- const session = neo4jPool.getSession(input.database);
3697
- try {
3773
+ return await withNeo4jSession(input.database, async (session) => {
3698
3774
  let cypher = `MATCH (n:${safeLabel})`;
3699
3775
  let parameters = {};
3700
3776
  if (input.properties && Object.keys(input.properties).length > 0) {
@@ -3716,9 +3792,7 @@ function createNeo4jFindNodesTool() {
3716
3792
  limit: input.limit
3717
3793
  }
3718
3794
  };
3719
- } finally {
3720
- await session.close();
3721
- }
3795
+ });
3722
3796
  } catch (error) {
3723
3797
  return {
3724
3798
  success: false,
@@ -3744,8 +3818,7 @@ function createNeo4jTraverseTool() {
3744
3818
  try {
3745
3819
  const safeDirection = validateDirection(input.direction || "outgoing");
3746
3820
  const safeRelType = input.relationshipType ? validateRelationshipType(input.relationshipType) : null;
3747
- const session = neo4jPool.getSession(input.database);
3748
- try {
3821
+ return await withNeo4jSession(input.database, async (session) => {
3749
3822
  let relPattern = "";
3750
3823
  if (safeDirection === "OUTGOING") {
3751
3824
  relPattern = safeRelType ? `-[r:${safeRelType}*1..${input.maxDepth}]->` : `-[r*1..${input.maxDepth}]->`;
@@ -3782,9 +3855,7 @@ function createNeo4jTraverseTool() {
3782
3855
  maxDepth: input.maxDepth
3783
3856
  }
3784
3857
  };
3785
- } finally {
3786
- await session.close();
3787
- }
3858
+ });
3788
3859
  } catch (error) {
3789
3860
  return {
3790
3861
  success: false,
@@ -3809,8 +3880,7 @@ function createNeo4jVectorSearchTool() {
3809
3880
  };
3810
3881
  }
3811
3882
  try {
3812
- const session = neo4jPool.getSession(input.database);
3813
- try {
3883
+ return await withNeo4jSession(input.database, async (session) => {
3814
3884
  const cypher = `
3815
3885
  CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
3816
3886
  YIELD node, score
@@ -3837,9 +3907,7 @@ function createNeo4jVectorSearchTool() {
3837
3907
  limit: input.limit
3838
3908
  }
3839
3909
  };
3840
- } finally {
3841
- await session.close();
3842
- }
3910
+ });
3843
3911
  } catch (error) {
3844
3912
  const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search";
3845
3913
  let helpText = "";
@@ -3885,8 +3953,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
3885
3953
  });
3886
3954
  try {
3887
3955
  const embeddingResult = await embeddingManager.generateEmbedding(input.queryText, input.model);
3888
- const session = neo4jPool.getSession(input.database);
3889
- try {
3956
+ return await withNeo4jSession(input.database, async (session) => {
3890
3957
  const cypher = `
3891
3958
  CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
3892
3959
  YIELD node, score
@@ -3928,9 +3995,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
3928
3995
  usage: embeddingResult.usage
3929
3996
  }
3930
3997
  };
3931
- } finally {
3932
- await session.close();
3933
- }
3998
+ });
3934
3999
  } catch (error) {
3935
4000
  const duration = Date.now() - startTime;
3936
4001
  const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search with embedding";
@@ -3986,8 +4051,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
3986
4051
  const embeddingResult = await embeddingManager.generateEmbedding(textToEmbed, input.model);
3987
4052
  const safeLabel = validateLabel(input.label);
3988
4053
  const safeEmbeddingProp = validatePropertyKey(input.embeddingProperty || "embedding");
3989
- const session = neo4jPool.getSession(input.database);
3990
- try {
4054
+ return await withNeo4jSession(input.database, async (session) => {
3991
4055
  const allProperties = {
3992
4056
  ...input.properties
3993
4057
  };
@@ -4021,9 +4085,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
4021
4085
  },
4022
4086
  message: `Created node with label '${input.label}' and ${embeddingResult.dimensions}-dimensional embedding`
4023
4087
  };
4024
- } finally {
4025
- await session.close();
4026
- }
4088
+ });
4027
4089
  } catch (error) {
4028
4090
  const errorMessage = error instanceof Error ? error.message : "Failed to create node with embedding";
4029
4091
  let helpText = "";
@@ -10310,49 +10372,57 @@ var fileSearchSchema = z.object({
10310
10372
  recursive: z.boolean().default(true).describe("Search in subdirectories"),
10311
10373
  caseSensitive: z.boolean().default(false).describe("Case-sensitive pattern matching")
10312
10374
  });
10375
+ async function* traverseDirectory(directory, recursive) {
10376
+ const entries = await promises.readdir(directory, { withFileTypes: true });
10377
+ for (const entry of entries) {
10378
+ const fullPath = path.join(directory, entry.name);
10379
+ const isDirectory = entry.isDirectory();
10380
+ yield {
10381
+ name: entry.name,
10382
+ fullPath,
10383
+ isFile: entry.isFile(),
10384
+ isDirectory
10385
+ };
10386
+ if (recursive && isDirectory) {
10387
+ yield* traverseDirectory(fullPath, true);
10388
+ }
10389
+ }
10390
+ }
10391
+
10392
+ // src/file/directory/tools/directory-list.ts
10313
10393
  function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
10314
10394
  return toolBuilder().name("directory-list").description("List all files and directories in a directory. Can optionally include file details and filter by extension.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "list", "files", "filesystem"]).schema(directoryListSchema).implementSafe(async (input) => {
10315
10395
  const safePath = await policy.resolvePath(input.path, "directory listing");
10316
10396
  const includeDetails = input.includeDetails ?? defaultIncludeDetails;
10317
- const listFiles = async (dir, recursive2) => {
10318
- const entries = await promises.readdir(dir, { withFileTypes: true });
10319
- const files2 = [];
10320
- for (const entry of entries) {
10321
- const fullPath = path.join(dir, entry.name);
10322
- const relativePath = path.relative(safePath, fullPath);
10323
- if (input.extension && !entry.name.endsWith(input.extension)) {
10324
- if (!entry.isDirectory() || !recursive2) {
10325
- continue;
10326
- }
10327
- }
10328
- if (includeDetails) {
10329
- const stats = await promises.lstat(fullPath);
10330
- files2.push({
10331
- name: entry.name,
10332
- path: relativePath,
10333
- fullPath,
10334
- isFile: entry.isFile(),
10335
- isDirectory: entry.isDirectory(),
10336
- size: stats.size,
10337
- modified: stats.mtime.toISOString()
10338
- });
10339
- } else {
10340
- files2.push({
10341
- name: entry.name,
10342
- path: relativePath,
10343
- isFile: entry.isFile(),
10344
- isDirectory: entry.isDirectory()
10345
- });
10346
- }
10347
- if (recursive2 && entry.isDirectory()) {
10348
- const subFiles = await listFiles(fullPath, true);
10349
- files2.push(...subFiles);
10397
+ const recursive = input.recursive ?? defaultRecursive;
10398
+ const files = [];
10399
+ for await (const entry of traverseDirectory(safePath, recursive)) {
10400
+ const relativePath = path.relative(safePath, entry.fullPath);
10401
+ if (input.extension && !entry.name.endsWith(input.extension)) {
10402
+ if (!entry.isDirectory || !recursive) {
10403
+ continue;
10350
10404
  }
10351
10405
  }
10352
- return files2;
10353
- };
10354
- const recursive = input.recursive ?? defaultRecursive;
10355
- const files = await listFiles(safePath, recursive);
10406
+ if (includeDetails) {
10407
+ const stats = await promises.lstat(entry.fullPath);
10408
+ files.push({
10409
+ name: entry.name,
10410
+ path: relativePath,
10411
+ fullPath: entry.fullPath,
10412
+ isFile: entry.isFile,
10413
+ isDirectory: entry.isDirectory,
10414
+ size: stats.size,
10415
+ modified: stats.mtime.toISOString()
10416
+ });
10417
+ } else {
10418
+ files.push({
10419
+ name: entry.name,
10420
+ path: relativePath,
10421
+ isFile: entry.isFile,
10422
+ isDirectory: entry.isDirectory
10423
+ });
10424
+ }
10425
+ }
10356
10426
  const result = {
10357
10427
  path: input.path,
10358
10428
  files,
@@ -10388,24 +10458,14 @@ function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = fa
10388
10458
  const recursive = input.recursive ?? defaultRecursive;
10389
10459
  const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
10390
10460
  const safeDirectory = await policy.resolvePath(input.directory, "file search");
10391
- const searchFiles = async (dir) => {
10392
- const entries = await promises.readdir(dir, { withFileTypes: true });
10393
- const matches2 = [];
10394
- const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
10395
- const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
10396
- for (const entry of entries) {
10397
- const fullPath = path.join(dir, entry.name);
10398
- if (entry.isFile() && regex.test(entry.name)) {
10399
- matches2.push(fullPath);
10400
- }
10401
- if (recursive && entry.isDirectory()) {
10402
- const subMatches = await searchFiles(fullPath);
10403
- matches2.push(...subMatches);
10404
- }
10461
+ const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
10462
+ const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
10463
+ const matches = [];
10464
+ for await (const entry of traverseDirectory(safeDirectory, recursive)) {
10465
+ if (entry.isFile && regex.test(entry.name)) {
10466
+ matches.push(entry.fullPath);
10405
10467
  }
10406
- return matches2;
10407
- };
10408
- const matches = await searchFiles(safeDirectory);
10468
+ }
10409
10469
  return {
10410
10470
  directory: input.directory,
10411
10471
  pattern: input.pattern,
@@ -11367,11 +11427,11 @@ var AskHumanInputSchema = z.object({
11367
11427
  });
11368
11428
  var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
11369
11429
  var logger19 = createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
11370
- function isRecord3(value) {
11430
+ function isRecord4(value) {
11371
11431
  return typeof value === "object" && value !== null;
11372
11432
  }
11373
11433
  function resolveInterrupt(module) {
11374
- if (!isRecord3(module)) {
11434
+ if (!isRecord4(module)) {
11375
11435
  return void 0;
11376
11436
  }
11377
11437
  const candidate = module.interrupt;