@agentforge/tools 0.18.3 → 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.cjs CHANGED
@@ -3,7 +3,7 @@
3
3
  var core = require('@agentforge/core');
4
4
  var promises = require('dns/promises');
5
5
  var net = require('net');
6
- var axios11 = require('axios');
6
+ var axios5 = require('axios');
7
7
  var zod = require('zod');
8
8
  var cheerio = require('cheerio');
9
9
  var webApi = require('@slack/web-api');
@@ -41,7 +41,7 @@ function _interopNamespace(e) {
41
41
  }
42
42
 
43
43
  var net__default = /*#__PURE__*/_interopDefault(net);
44
- var axios11__default = /*#__PURE__*/_interopDefault(axios11);
44
+ var axios5__default = /*#__PURE__*/_interopDefault(axios5);
45
45
  var cheerio__namespace = /*#__PURE__*/_interopNamespace(cheerio);
46
46
  var neo4j__default = /*#__PURE__*/_interopDefault(neo4j);
47
47
  var path__namespace = /*#__PURE__*/_interopNamespace(path);
@@ -229,7 +229,7 @@ async function requestWithDestinationPolicy(config, policy = {}) {
229
229
  for (let redirectCount = 0; ; redirectCount += 1) {
230
230
  const validatedAddresses = await validateDestinationAllowed(currentUrl, effectivePolicy);
231
231
  currentConfig.lookup = createPinnedLookup(validatedAddresses);
232
- const response = await axios11__default.default(currentConfig);
232
+ const response = await axios5__default.default(currentConfig);
233
233
  if (!isRedirectStatus(response.status)) return response;
234
234
  if (effectivePolicy.allowRedirects === false) blockDestination(currentUrl, "redirect");
235
235
  if (redirectCount >= maxRedirects) throw new DestinationPolicyError(currentUrl, "redirect", `Maximum redirect count (${maxRedirects}) exceeded for ${currentUrl}`);
@@ -738,26 +738,23 @@ var DuckDuckGoProvider = class {
738
738
  * @param timeout - Request timeout in milliseconds (default: 30000)
739
739
  */
740
740
  async search(query, maxResults, timeout = DEFAULT_TIMEOUT) {
741
- return retryWithBackoff(async () => {
742
- try {
743
- const response = await axios11__default.default.get(
744
- "https://api.duckduckgo.com/",
745
- {
746
- params: {
747
- q: query,
748
- format: "json"
749
- },
750
- headers: {
751
- "User-Agent": "Mozilla/5.0 (compatible; AgentForge/1.0; +https://github.com/agentforge)"
752
- },
753
- timeout
754
- }
755
- );
741
+ try {
742
+ return await retryWithBackoff(async () => {
743
+ const response = await axios5__default.default.get("https://api.duckduckgo.com/", {
744
+ params: {
745
+ q: query,
746
+ format: "json"
747
+ },
748
+ headers: {
749
+ "User-Agent": "Mozilla/5.0 (compatible; AgentForge/1.0; +https://github.com/agentforge)"
750
+ },
751
+ timeout
752
+ });
756
753
  return this.normalizeResults(response.data, maxResults);
757
- } catch (error) {
758
- throw new Error(`DuckDuckGo search failed: ${error.message}`);
759
- }
760
- });
754
+ });
755
+ } catch (error) {
756
+ throw new Error(`DuckDuckGo search failed: ${error.message}`);
757
+ }
761
758
  }
762
759
  /**
763
760
  * Normalize DuckDuckGo response to SearchResult[]
@@ -842,9 +839,9 @@ var SerperProvider = class {
842
839
  "Serper API key not found. Set SERPER_API_KEY environment variable. Get your key at https://serper.dev"
843
840
  );
844
841
  }
845
- return retryWithBackoff(async () => {
846
- try {
847
- const response = await axios11__default.default.post(
842
+ try {
843
+ return await retryWithBackoff(async () => {
844
+ const response = await axios5__default.default.post(
848
845
  "https://google.serper.dev/search",
849
846
  {
850
847
  q: query,
@@ -859,20 +856,18 @@ var SerperProvider = class {
859
856
  }
860
857
  );
861
858
  return this.normalizeResults(response.data, maxResults);
862
- } catch (error) {
863
- if (error.response?.status === 401) {
864
- throw new Error(
865
- "Invalid Serper API key. Get your key at https://serper.dev"
866
- );
867
- }
868
- if (error.response?.status === 429) {
869
- throw new Error(
870
- "Serper API rate limit exceeded. Please try again later or upgrade your plan at https://serper.dev"
871
- );
872
- }
873
- throw new Error(`Serper search failed: ${error.message}`);
859
+ });
860
+ } catch (error) {
861
+ if (error.response?.status === 401) {
862
+ throw new Error("Invalid Serper API key. Get your key at https://serper.dev");
874
863
  }
875
- });
864
+ if (error.response?.status === 429) {
865
+ throw new Error(
866
+ "Serper API rate limit exceeded. Please try again later or upgrade your plan at https://serper.dev"
867
+ );
868
+ }
869
+ throw new Error(`Serper search failed: ${error.message}`);
870
+ }
876
871
  }
877
872
  /**
878
873
  * Normalize Serper response to SearchResult[]
@@ -1249,38 +1244,91 @@ function createGetConfiguredAuth(apiKey, email, siteUrl) {
1249
1244
  return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
1250
1245
  };
1251
1246
  }
1252
- function createGetConfiguredAuthHeader(getConfiguredAuth) {
1253
- return function getConfiguredAuthHeader() {
1254
- const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfiguredAuth();
1255
- const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1256
- return `Basic ${auth2}`;
1257
- };
1258
- }
1259
1247
  function getConfig() {
1260
1248
  const ATLASSIAN_API_KEY = process.env.ATLASSIAN_API_KEY || "";
1261
1249
  const ATLASSIAN_EMAIL = process.env.ATLASSIAN_EMAIL || "";
1262
1250
  const ATLASSIAN_SITE_URL = (process.env.ATLASSIAN_SITE_URL || "").replace(/\/$/, "");
1263
1251
  if (!ATLASSIAN_API_KEY || !ATLASSIAN_EMAIL || !ATLASSIAN_SITE_URL) {
1264
- throw new Error("Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env");
1252
+ throw new Error(
1253
+ "Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env"
1254
+ );
1265
1255
  }
1266
1256
  return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
1267
1257
  }
1268
- function getAuthHeader() {
1269
- const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfig();
1270
- const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1271
- return `Basic ${auth2}`;
1258
+ function isRecord(value) {
1259
+ return typeof value === "object" && value !== null;
1260
+ }
1261
+ function describeError(error) {
1262
+ const errorRecord = isRecord(error) ? error : void 0;
1263
+ const response = isRecord(errorRecord?.response) ? errorRecord.response : void 0;
1264
+ const responseData = isRecord(response?.data) ? response.data : void 0;
1265
+ const providerMessage = typeof responseData?.message === "string" ? responseData.message : void 0;
1266
+ const errorMessage = typeof errorRecord?.message === "string" ? errorRecord.message : void 0;
1267
+ return {
1268
+ message: providerMessage || errorMessage,
1269
+ status: typeof response?.status === "number" ? response.status : void 0
1270
+ };
1272
1271
  }
1273
- function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1274
- return core.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(core.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(zod.z.object({
1275
- query: zod.z.string().describe("Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"),
1276
- limit: zod.z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1277
- })).implement(async ({ query, limit = 10 }) => {
1272
+ function authenticatedConfig(auth2, config = {}) {
1273
+ const credentials = Buffer.from(`${auth2.ATLASSIAN_EMAIL}:${auth2.ATLASSIAN_API_KEY}`).toString(
1274
+ "base64"
1275
+ );
1276
+ return {
1277
+ ...config,
1278
+ headers: {
1279
+ ...config.headers,
1280
+ Authorization: `Basic ${credentials}`
1281
+ }
1282
+ };
1283
+ }
1284
+ function createConfluenceRequest(getAuth) {
1285
+ return {
1286
+ async get(path13, config = {}) {
1287
+ const auth2 = getAuth();
1288
+ const response = await axios5__default.default.get(
1289
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1290
+ authenticatedConfig(auth2, config)
1291
+ );
1292
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1293
+ },
1294
+ async post(path13, data, config = {}) {
1295
+ const auth2 = getAuth();
1296
+ const response = await axios5__default.default.post(
1297
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1298
+ data,
1299
+ authenticatedConfig(auth2, config)
1300
+ );
1301
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1302
+ },
1303
+ async put(path13, data, config = {}) {
1304
+ const auth2 = getAuth();
1305
+ const response = await axios5__default.default.put(
1306
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1307
+ data,
1308
+ authenticatedConfig(auth2, config)
1309
+ );
1310
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1311
+ },
1312
+ describeError
1313
+ };
1314
+ }
1315
+ function createSearchConfluenceTool(request2, logger20) {
1316
+ return core.toolBuilder().name("search-confluence").description(
1317
+ "Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts."
1318
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes(
1319
+ "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."
1320
+ ).suggests(["get-confluence-page"]).schema(
1321
+ zod.z.object({
1322
+ query: zod.z.string().describe(
1323
+ "Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"
1324
+ ),
1325
+ limit: zod.z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1326
+ })
1327
+ ).implement(async ({ query, limit = 10 }) => {
1278
1328
  logger20.info("search-confluence called", { query, limit });
1279
1329
  try {
1280
- const { ATLASSIAN_SITE_URL } = getAuth();
1281
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
1330
+ const response = await request2.get("/wiki/rest/api/content/search", {
1282
1331
  headers: {
1283
- Authorization: getAuthHeader2(),
1284
1332
  Accept: "application/json"
1285
1333
  },
1286
1334
  params: {
@@ -1289,22 +1337,24 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1289
1337
  expand: "space,version"
1290
1338
  }
1291
1339
  });
1292
- const { ATLASSIAN_SITE_URL: siteUrl } = getAuth();
1293
1340
  const results = response.data.results.map((page) => ({
1294
1341
  id: page.id,
1295
1342
  title: page.title,
1296
1343
  type: page.type,
1297
1344
  space: page.space?.name || "Unknown",
1298
1345
  spaceKey: page.space?.key || "",
1299
- url: `${siteUrl}/wiki${page._links.webui}`,
1346
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1300
1347
  lastModified: page.version?.when || ""
1301
1348
  }));
1302
1349
  if (results.length === 0) {
1303
- logger20.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
1304
- query,
1305
- limit,
1306
- totalSize: response.data.totalSize
1307
- });
1350
+ logger20.warn(
1351
+ "search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry",
1352
+ {
1353
+ query,
1354
+ limit,
1355
+ totalSize: response.data.totalSize
1356
+ }
1357
+ );
1308
1358
  } else {
1309
1359
  logger20.info("search-confluence result", {
1310
1360
  query,
@@ -1321,28 +1371,33 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1321
1371
  results
1322
1372
  });
1323
1373
  } catch (error) {
1374
+ const description = request2.describeError(error);
1324
1375
  logger20.error("search-confluence error", {
1325
1376
  query,
1326
- error: error.response?.data?.message || error.message,
1327
- status: error.response?.status
1377
+ ...description.message !== void 0 ? { error: description.message } : {},
1378
+ ...description.status !== void 0 ? { status: description.status } : {}
1328
1379
  });
1329
1380
  return JSON.stringify({
1330
1381
  success: false,
1331
- error: error.response?.data?.message || error.message
1382
+ error: description.message
1332
1383
  });
1333
1384
  }
1334
1385
  }).build();
1335
1386
  }
1336
- function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1337
- return core.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(core.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(zod.z.object({
1338
- page_id: zod.z.string().describe("The Confluence page ID (from search results)")
1339
- })).implement(async ({ page_id }) => {
1387
+ function createGetConfluencePageTool(request2, logger20) {
1388
+ return core.toolBuilder().name("get-confluence-page").description(
1389
+ "Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata."
1390
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes(
1391
+ "Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results."
1392
+ ).requires(["search-confluence"]).schema(
1393
+ zod.z.object({
1394
+ page_id: zod.z.string().describe("The Confluence page ID (from search results)")
1395
+ })
1396
+ ).implement(async ({ page_id }) => {
1340
1397
  logger20.info("get-confluence-page called", { page_id });
1341
1398
  try {
1342
- const { ATLASSIAN_SITE_URL } = getAuth();
1343
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
1399
+ const response = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1344
1400
  headers: {
1345
- Authorization: getAuthHeader2(),
1346
1401
  Accept: "application/json"
1347
1402
  },
1348
1403
  params: {
@@ -1365,35 +1420,40 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1365
1420
  space: page.space?.name || "Unknown",
1366
1421
  spaceKey: page.space?.key || "",
1367
1422
  content: page.body?.storage?.value || "",
1368
- url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
1423
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1369
1424
  created: page.history?.createdDate || "",
1370
1425
  lastModified: page.version?.when || "",
1371
1426
  version: page.version?.number || 1
1372
1427
  }
1373
1428
  });
1374
1429
  } catch (error) {
1430
+ const description = request2.describeError(error);
1375
1431
  logger20.error("get-confluence-page error", {
1376
1432
  page_id,
1377
- error: error.response?.data?.message || error.message,
1378
- status: error.response?.status
1433
+ ...description.message !== void 0 ? { error: description.message } : {},
1434
+ ...description.status !== void 0 ? { status: description.status } : {}
1379
1435
  });
1380
1436
  return JSON.stringify({
1381
1437
  success: false,
1382
- error: error.response?.data?.message || error.message
1438
+ error: description.message
1383
1439
  });
1384
1440
  }
1385
1441
  }).build();
1386
1442
  }
1387
- function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1388
- return core.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(core.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(zod.z.object({
1389
- limit: zod.z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1390
- })).implement(async ({ limit = 25 }) => {
1443
+ function createListConfluenceSpacesTool(request2, logger20) {
1444
+ return core.toolBuilder().name("list-confluence-spaces").description(
1445
+ "List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information."
1446
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes(
1447
+ "Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance')."
1448
+ ).follows(["search-confluence"]).schema(
1449
+ zod.z.object({
1450
+ limit: zod.z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1451
+ })
1452
+ ).implement(async ({ limit = 25 }) => {
1391
1453
  logger20.info("list-confluence-spaces called", { limit });
1392
1454
  try {
1393
- const { ATLASSIAN_SITE_URL } = getAuth();
1394
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
1455
+ const response = await request2.get("/wiki/rest/api/space", {
1395
1456
  headers: {
1396
- Authorization: getAuthHeader2(),
1397
1457
  Accept: "application/json"
1398
1458
  },
1399
1459
  params: {
@@ -1405,7 +1465,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1405
1465
  name: space.name,
1406
1466
  type: space.type,
1407
1467
  description: space.description?.plain?.value || "",
1408
- url: `${ATLASSIAN_SITE_URL}/wiki${space._links.webui}`
1468
+ url: `${response.siteUrl}/wiki${space._links.webui}`
1409
1469
  }));
1410
1470
  logger20.info("list-confluence-spaces result", {
1411
1471
  spaceCount: spaces.length,
@@ -1418,28 +1478,33 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1418
1478
  spaces
1419
1479
  });
1420
1480
  } catch (error) {
1481
+ const description = request2.describeError(error);
1421
1482
  logger20.error("list-confluence-spaces error", {
1422
- error: error.response?.data?.message || error.message,
1423
- status: error.response?.status
1483
+ ...description.message !== void 0 ? { error: description.message } : {},
1484
+ ...description.status !== void 0 ? { status: description.status } : {}
1424
1485
  });
1425
1486
  return JSON.stringify({
1426
1487
  success: false,
1427
- error: error.response?.data?.message || error.message
1488
+ error: description.message
1428
1489
  });
1429
1490
  }
1430
1491
  }).build();
1431
1492
  }
1432
- function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1433
- return core.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(core.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(zod.z.object({
1434
- space_key: zod.z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1435
- limit: zod.z.number().optional().describe("Maximum number of pages to return (default: 25)")
1436
- })).implement(async ({ space_key, limit = 25 }) => {
1493
+ function createGetSpacePagesTool(request2, logger20) {
1494
+ return core.toolBuilder().name("get-space-pages").description(
1495
+ "Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area."
1496
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes(
1497
+ "Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first."
1498
+ ).requires(["list-confluence-spaces"]).schema(
1499
+ zod.z.object({
1500
+ space_key: zod.z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1501
+ limit: zod.z.number().optional().describe("Maximum number of pages to return (default: 25)")
1502
+ })
1503
+ ).implement(async ({ space_key, limit = 25 }) => {
1437
1504
  logger20.info("get-space-pages called", { space_key, limit });
1438
1505
  try {
1439
- const { ATLASSIAN_SITE_URL } = getAuth();
1440
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
1506
+ const response = await request2.get("/wiki/rest/api/content", {
1441
1507
  headers: {
1442
- Authorization: getAuthHeader2(),
1443
1508
  Accept: "application/json"
1444
1509
  },
1445
1510
  params: {
@@ -1452,14 +1517,17 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1452
1517
  const pages = response.data.results.map((page) => ({
1453
1518
  id: page.id,
1454
1519
  title: page.title,
1455
- url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
1520
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1456
1521
  lastModified: page.version?.when || ""
1457
1522
  }));
1458
1523
  if (pages.length === 0) {
1459
- logger20.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
1460
- space_key,
1461
- limit
1462
- });
1524
+ logger20.warn(
1525
+ "get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry",
1526
+ {
1527
+ space_key,
1528
+ limit
1529
+ }
1530
+ );
1463
1531
  } else {
1464
1532
  logger20.info("get-space-pages result", {
1465
1533
  space_key,
@@ -1475,28 +1543,38 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1475
1543
  pages
1476
1544
  });
1477
1545
  } catch (error) {
1546
+ const description = request2.describeError(error);
1478
1547
  logger20.error("get-space-pages error", {
1479
1548
  space_key,
1480
- error: error.response?.data?.message || error.message,
1481
- status: error.response?.status
1549
+ ...description.message !== void 0 ? { error: description.message } : {},
1550
+ ...description.status !== void 0 ? { status: description.status } : {}
1482
1551
  });
1483
1552
  return JSON.stringify({
1484
1553
  success: false,
1485
- error: error.response?.data?.message || error.message
1554
+ error: description.message
1486
1555
  });
1487
1556
  }
1488
1557
  }).build();
1489
1558
  }
1490
- function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1491
- return core.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(core.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(zod.z.object({
1492
- space_key: zod.z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1493
- title: zod.z.string().describe("The title of the new page"),
1494
- content: zod.z.string().describe("The page content in HTML format (Confluence storage format)"),
1495
- parent_page_id: zod.z.string().optional().describe("Optional parent page ID to create this as a child page")
1496
- })).implement(async ({ space_key, title, content, parent_page_id }) => {
1497
- logger20.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
1559
+ function createCreateConfluencePageTool(request2, logger20) {
1560
+ return core.toolBuilder().name("create-confluence-page").description(
1561
+ "Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format)."
1562
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes(
1563
+ "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."
1564
+ ).requires(["list-confluence-spaces"]).schema(
1565
+ zod.z.object({
1566
+ space_key: zod.z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1567
+ title: zod.z.string().describe("The title of the new page"),
1568
+ content: zod.z.string().describe("The page content in HTML format (Confluence storage format)"),
1569
+ parent_page_id: zod.z.string().optional().describe("Optional parent page ID to create this as a child page")
1570
+ })
1571
+ ).implement(async ({ space_key, title, content, parent_page_id }) => {
1572
+ logger20.info("create-confluence-page called", {
1573
+ space_key,
1574
+ title,
1575
+ hasParent: !!parent_page_id
1576
+ });
1498
1577
  try {
1499
- const { ATLASSIAN_SITE_URL } = getAuth();
1500
1578
  const pageData = {
1501
1579
  type: "page",
1502
1580
  title,
@@ -1511,16 +1589,11 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1511
1589
  if (parent_page_id) {
1512
1590
  pageData.ancestors = [{ id: parent_page_id }];
1513
1591
  }
1514
- const response = await axios11__default.default.post(
1515
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content`,
1516
- pageData,
1517
- {
1518
- headers: {
1519
- Authorization: getAuthHeader2(),
1520
- "Content-Type": "application/json"
1521
- }
1592
+ const response = await request2.post("/wiki/rest/api/content", pageData, {
1593
+ headers: {
1594
+ "Content-Type": "application/json"
1522
1595
  }
1523
- );
1596
+ });
1524
1597
  logger20.info("create-confluence-page result", {
1525
1598
  page_id: response.data.id,
1526
1599
  title: response.data.title,
@@ -1532,45 +1605,45 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1532
1605
  id: response.data.id,
1533
1606
  title: response.data.title,
1534
1607
  space: space_key,
1535
- url: `${ATLASSIAN_SITE_URL}/wiki${response.data._links.webui}`,
1608
+ url: `${response.siteUrl}/wiki${response.data._links.webui}`,
1536
1609
  version: response.data.version?.number || 1
1537
1610
  }
1538
1611
  });
1539
1612
  } catch (error) {
1613
+ const description = request2.describeError(error);
1540
1614
  logger20.error("create-confluence-page error", {
1541
1615
  space_key,
1542
1616
  title,
1543
- error: error.response?.data?.message || error.message,
1544
- status: error.response?.status
1617
+ ...description.message !== void 0 ? { error: description.message } : {},
1618
+ ...description.status !== void 0 ? { status: description.status } : {}
1545
1619
  });
1546
1620
  return JSON.stringify({
1547
1621
  success: false,
1548
- error: error.response?.data?.message || error.message
1622
+ error: description.message
1549
1623
  });
1550
1624
  }
1551
1625
  }).build();
1552
1626
  }
1553
- function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1554
- return core.toolBuilder().name("update-confluence-page").description("Update an existing Confluence page's content. Requires page ID, new title, and new content.").category(core.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(zod.z.object({
1555
- page_id: zod.z.string().describe("The ID of the page to update"),
1556
- title: zod.z.string().describe("The new title for the page"),
1557
- content: zod.z.string().describe("The new content in HTML format (Confluence storage format)")
1558
- })).implement(async ({ page_id, title, content }) => {
1627
+ function createUpdateConfluencePageTool(request2, logger20) {
1628
+ return core.toolBuilder().name("update-confluence-page").description(
1629
+ "Update an existing Confluence page's content. Requires page ID, new title, and new content."
1630
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes(
1631
+ "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."
1632
+ ).requires(["get-confluence-page"]).schema(
1633
+ zod.z.object({
1634
+ page_id: zod.z.string().describe("The ID of the page to update"),
1635
+ title: zod.z.string().describe("The new title for the page"),
1636
+ content: zod.z.string().describe("The new content in HTML format (Confluence storage format)")
1637
+ })
1638
+ ).implement(async ({ page_id, title, content }) => {
1559
1639
  logger20.info("update-confluence-page called", { page_id, title });
1560
1640
  try {
1561
- const { ATLASSIAN_SITE_URL } = getAuth();
1562
- const getResponse = await axios11__default.default.get(
1563
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1564
- {
1565
- headers: {
1566
- Authorization: getAuthHeader2()
1567
- },
1568
- params: { expand: "version" }
1569
- }
1570
- );
1641
+ const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1642
+ params: { expand: "version" }
1643
+ });
1571
1644
  const currentVersion = getResponse.data.version.number;
1572
- const updateResponse = await axios11__default.default.put(
1573
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1645
+ const updateResponse = await request2.put(
1646
+ `/wiki/rest/api/content/${page_id}`,
1574
1647
  {
1575
1648
  type: "page",
1576
1649
  title,
@@ -1584,7 +1657,6 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1584
1657
  },
1585
1658
  {
1586
1659
  headers: {
1587
- Authorization: getAuthHeader2(),
1588
1660
  "Content-Type": "application/json"
1589
1661
  }
1590
1662
  }
@@ -1600,49 +1672,49 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1600
1672
  page: {
1601
1673
  id: updateResponse.data.id,
1602
1674
  title: updateResponse.data.title,
1603
- url: `${ATLASSIAN_SITE_URL}/wiki${updateResponse.data._links.webui}`,
1675
+ url: `${updateResponse.siteUrl}/wiki${updateResponse.data._links.webui}`,
1604
1676
  version: updateResponse.data.version.number,
1605
1677
  previousVersion: currentVersion
1606
1678
  }
1607
1679
  });
1608
1680
  } catch (error) {
1681
+ const description = request2.describeError(error);
1609
1682
  logger20.error("update-confluence-page error", {
1610
1683
  page_id,
1611
1684
  title,
1612
- error: error.response?.data?.message || error.message,
1613
- status: error.response?.status
1685
+ ...description.message !== void 0 ? { error: description.message } : {},
1686
+ ...description.status !== void 0 ? { status: description.status } : {}
1614
1687
  });
1615
1688
  return JSON.stringify({
1616
1689
  success: false,
1617
- error: error.response?.data?.message || error.message
1690
+ error: description.message
1618
1691
  });
1619
1692
  }
1620
1693
  }).build();
1621
1694
  }
1622
- function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1623
- return core.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(core.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(zod.z.object({
1624
- page_id: zod.z.string().describe("The ID of the page to archive"),
1625
- reason: zod.z.string().optional().describe("Optional reason for archiving (for audit trail)")
1626
- })).implement(async ({ page_id, reason }) => {
1695
+ function createArchiveConfluencePageTool(request2, logger20) {
1696
+ return core.toolBuilder().name("archive-confluence-page").description(
1697
+ "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."
1698
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes(
1699
+ "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."
1700
+ ).conflicts(["create-confluence-page"]).schema(
1701
+ zod.z.object({
1702
+ page_id: zod.z.string().describe("The ID of the page to archive"),
1703
+ reason: zod.z.string().optional().describe("Optional reason for archiving (for audit trail)")
1704
+ })
1705
+ ).implement(async ({ page_id, reason }) => {
1627
1706
  logger20.info("archive-confluence-page called", {
1628
1707
  page_id,
1629
1708
  ...reason ? { reason } : {}
1630
1709
  });
1631
1710
  try {
1632
- const { ATLASSIAN_SITE_URL } = getAuth();
1633
- const getResponse = await axios11__default.default.get(
1634
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1635
- {
1636
- headers: {
1637
- Authorization: getAuthHeader2()
1638
- },
1639
- params: { expand: "version,body.storage,space" }
1640
- }
1641
- );
1711
+ const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1712
+ params: { expand: "version,body.storage,space" }
1713
+ });
1642
1714
  const currentVersion = getResponse.data.version.number;
1643
1715
  const pageData = getResponse.data;
1644
- await axios11__default.default.put(
1645
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1716
+ await request2.put(
1717
+ `/wiki/rest/api/content/${page_id}`,
1646
1718
  {
1647
1719
  version: { number: currentVersion + 1 },
1648
1720
  title: pageData.title,
@@ -1653,7 +1725,6 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1653
1725
  },
1654
1726
  {
1655
1727
  headers: {
1656
- Authorization: getAuthHeader2(),
1657
1728
  "Content-Type": "application/json"
1658
1729
  }
1659
1730
  }
@@ -1676,14 +1747,15 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1676
1747
  }
1677
1748
  });
1678
1749
  } catch (error) {
1750
+ const description = request2.describeError(error);
1679
1751
  logger20.error("archive-confluence-page error", {
1680
1752
  page_id,
1681
- error: error.response?.data?.message || error.message,
1682
- status: error.response?.status
1753
+ ...description.message !== void 0 ? { error: description.message } : {},
1754
+ ...description.status !== void 0 ? { status: description.status } : {}
1683
1755
  });
1684
1756
  return JSON.stringify({
1685
1757
  success: false,
1686
- error: error.response?.data?.message || error.message
1758
+ error: description.message
1687
1759
  });
1688
1760
  }
1689
1761
  }).build();
@@ -1692,13 +1764,14 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1692
1764
  // src/web/confluence/index.ts
1693
1765
  var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
1694
1766
  var logger2 = core.createLogger("[tools:confluence]", { level: logLevel2 });
1695
- var searchConfluence = createSearchConfluenceTool(getConfig, getAuthHeader, logger2);
1696
- var getConfluencePage = createGetConfluencePageTool(getConfig, getAuthHeader, logger2);
1697
- var listConfluenceSpaces = createListConfluenceSpacesTool(getConfig, getAuthHeader, logger2);
1698
- var getSpacePages = createGetSpacePagesTool(getConfig, getAuthHeader, logger2);
1699
- var createConfluencePage = createCreateConfluencePageTool(getConfig, getAuthHeader, logger2);
1700
- var updateConfluencePage = createUpdateConfluencePageTool(getConfig, getAuthHeader, logger2);
1701
- var archiveConfluencePage = createArchiveConfluencePageTool(getConfig, getAuthHeader, logger2);
1767
+ var request = createConfluenceRequest(getConfig);
1768
+ var searchConfluence = createSearchConfluenceTool(request, logger2);
1769
+ var getConfluencePage = createGetConfluencePageTool(request, logger2);
1770
+ var listConfluenceSpaces = createListConfluenceSpacesTool(request, logger2);
1771
+ var getSpacePages = createGetSpacePagesTool(request, logger2);
1772
+ var createConfluencePage = createCreateConfluencePageTool(request, logger2);
1773
+ var updateConfluencePage = createUpdateConfluencePageTool(request, logger2);
1774
+ var archiveConfluencePage = createArchiveConfluencePageTool(request, logger2);
1702
1775
  var confluenceTools = [
1703
1776
  // Read tools
1704
1777
  searchConfluence,
@@ -1711,22 +1784,17 @@ var confluenceTools = [
1711
1784
  archiveConfluencePage
1712
1785
  ];
1713
1786
  function createConfluenceTools(config = {}) {
1714
- const {
1715
- apiKey,
1716
- email,
1717
- siteUrl,
1718
- logLevel: customLogLevel
1719
- } = config;
1787
+ const { apiKey, email, siteUrl, logLevel: customLogLevel } = config;
1720
1788
  const getConfiguredAuth = createGetConfiguredAuth(apiKey, email, siteUrl);
1721
- const getConfiguredAuthHeader = createGetConfiguredAuthHeader(getConfiguredAuth);
1789
+ const request2 = createConfluenceRequest(getConfiguredAuth);
1722
1790
  const toolLogger = customLogLevel ? core.createLogger("tools:confluence", { level: customLogLevel }) : logger2;
1723
- const searchConfluence2 = createSearchConfluenceTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1724
- const getConfluencePage2 = createGetConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1725
- const listConfluenceSpaces2 = createListConfluenceSpacesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1726
- const getSpacePages2 = createGetSpacePagesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1727
- const createConfluencePage2 = createCreateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1728
- const updateConfluencePage2 = createUpdateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1729
- const archiveConfluencePage2 = createArchiveConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1791
+ const searchConfluence2 = createSearchConfluenceTool(request2, toolLogger);
1792
+ const getConfluencePage2 = createGetConfluencePageTool(request2, toolLogger);
1793
+ const listConfluenceSpaces2 = createListConfluenceSpacesTool(request2, toolLogger);
1794
+ const getSpacePages2 = createGetSpacePagesTool(request2, toolLogger);
1795
+ const createConfluencePage2 = createCreateConfluencePageTool(request2, toolLogger);
1796
+ const updateConfluencePage2 = createUpdateConfluencePageTool(request2, toolLogger);
1797
+ const archiveConfluencePage2 = createArchiveConfluencePageTool(request2, toolLogger);
1730
1798
  return {
1731
1799
  searchConfluence: searchConfluence2,
1732
1800
  getConfluencePage: getConfluencePage2,
@@ -1917,14 +1985,14 @@ function createJsonStringifyTool(defaultIndent = 2, defaultPretty = false) {
1917
1985
  };
1918
1986
  }).build();
1919
1987
  }
1920
- function isRecord(value) {
1988
+ function isRecord2(value) {
1921
1989
  return typeof value === "object" && value !== null && !Array.isArray(value);
1922
1990
  }
1923
1991
  function getPathValue(current, part) {
1924
1992
  const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1925
1993
  if (arrayMatch) {
1926
1994
  const [, key, index] = arrayMatch;
1927
- if (!isRecord(current)) {
1995
+ if (!isRecord2(current)) {
1928
1996
  return void 0;
1929
1997
  }
1930
1998
  const candidate = current[key];
@@ -1933,7 +2001,7 @@ function getPathValue(current, part) {
1933
2001
  }
1934
2002
  return candidate[parseInt(index, 10)];
1935
2003
  }
1936
- if (!isRecord(current)) {
2004
+ if (!isRecord2(current)) {
1937
2005
  return void 0;
1938
2006
  }
1939
2007
  return current[part];
@@ -2589,7 +2657,7 @@ async function initializeFromEnv() {
2589
2657
  // src/data/neo4j/embeddings/utils.ts
2590
2658
  function withProviderErrorMetadata(error, message) {
2591
2659
  const wrappedError = new Error(message);
2592
- if (!isRecord2(error)) return wrappedError;
2660
+ if (!isRecord3(error)) return wrappedError;
2593
2661
  if (typeof error.code === "string") wrappedError.code = error.code;
2594
2662
  if (error.response !== void 0) wrappedError.response = error.response;
2595
2663
  return wrappedError;
@@ -2602,12 +2670,12 @@ var DEFAULT_RETRY_CONFIG2 = {
2602
2670
  // 10 seconds
2603
2671
  backoffMultiplier: 2
2604
2672
  };
2605
- function isRecord2(value) {
2673
+ function isRecord3(value) {
2606
2674
  return typeof value === "object" && value !== null;
2607
2675
  }
2608
2676
  function isRetryableError2(error) {
2609
- if (!isRecord2(error)) return false;
2610
- const response = isRecord2(error.response) ? error.response : void 0;
2677
+ if (!isRecord3(error)) return false;
2678
+ const response = isRecord3(error.response) ? error.response : void 0;
2611
2679
  const status = typeof response?.status === "number" ? response.status : void 0;
2612
2680
  const code = typeof error.code === "string" ? error.code : void 0;
2613
2681
  const message = typeof error.message === "string" ? error.message : void 0;
@@ -2733,7 +2801,7 @@ var OpenAIEmbeddingProvider = class {
2733
2801
  const modelToUse = model || this.defaultModel;
2734
2802
  return retryWithBackoff2(async () => {
2735
2803
  try {
2736
- const response = await axios11__default.default.post(
2804
+ const response = await axios5__default.default.post(
2737
2805
  `${this.baseURL}/embeddings`,
2738
2806
  {
2739
2807
  input: text,
@@ -2763,7 +2831,7 @@ var OpenAIEmbeddingProvider = class {
2763
2831
  };
2764
2832
  } catch (error) {
2765
2833
  let message;
2766
- const response = axios11__default.default.isAxiosError(error) ? error.response : void 0;
2834
+ const response = axios5__default.default.isAxiosError(error) ? error.response : void 0;
2767
2835
  if (response?.status === 401) {
2768
2836
  message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
2769
2837
  } else if (response?.status === 429) {
@@ -2790,7 +2858,7 @@ var OpenAIEmbeddingProvider = class {
2790
2858
  const modelToUse = model || this.defaultModel;
2791
2859
  return retryWithBackoff2(async () => {
2792
2860
  try {
2793
- const response = await axios11__default.default.post(
2861
+ const response = await axios5__default.default.post(
2794
2862
  `${this.baseURL}/embeddings`,
2795
2863
  {
2796
2864
  input: texts,
@@ -2821,7 +2889,7 @@ var OpenAIEmbeddingProvider = class {
2821
2889
  };
2822
2890
  } catch (error) {
2823
2891
  let message;
2824
- const response = axios11__default.default.isAxiosError(error) ? error.response : void 0;
2892
+ const response = axios5__default.default.isAxiosError(error) ? error.response : void 0;
2825
2893
  if (response?.status === 401) {
2826
2894
  message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
2827
2895
  } else if (response?.status === 429) {
@@ -2863,7 +2931,7 @@ var CohereEmbeddingProvider = class {
2863
2931
  const modelToUse = model || this.defaultModel;
2864
2932
  return retryWithBackoff2(async () => {
2865
2933
  try {
2866
- const response = await axios11__default.default.post(
2934
+ const response = await axios5__default.default.post(
2867
2935
  `${this.baseUrl}/embed`,
2868
2936
  {
2869
2937
  texts,
@@ -2891,7 +2959,7 @@ var CohereEmbeddingProvider = class {
2891
2959
  } : void 0
2892
2960
  };
2893
2961
  } catch (error) {
2894
- if (axios11__default.default.isAxiosError(error)) {
2962
+ if (axios5__default.default.isAxiosError(error)) {
2895
2963
  const status = error.response?.status;
2896
2964
  const providerMessage = error.response?.data?.message || error.message;
2897
2965
  let message;
@@ -2929,7 +2997,7 @@ var HuggingFaceEmbeddingProvider = class {
2929
2997
  const modelToUse = model || this.defaultModel;
2930
2998
  return retryWithBackoff2(async () => {
2931
2999
  try {
2932
- const response = await axios11__default.default.post(
3000
+ const response = await axios5__default.default.post(
2933
3001
  `${this.baseUrl}/${modelToUse}`,
2934
3002
  {
2935
3003
  inputs: text,
@@ -2951,7 +3019,7 @@ var HuggingFaceEmbeddingProvider = class {
2951
3019
  dimensions: embedding.length
2952
3020
  };
2953
3021
  } catch (error) {
2954
- if (axios11__default.default.isAxiosError(error)) {
3022
+ if (axios5__default.default.isAxiosError(error)) {
2955
3023
  const status = error.response?.status;
2956
3024
  const message = error.response?.data?.error || error.message;
2957
3025
  let messageText;
@@ -2976,7 +3044,7 @@ var HuggingFaceEmbeddingProvider = class {
2976
3044
  const modelToUse = model || this.defaultModel;
2977
3045
  return retryWithBackoff2(async () => {
2978
3046
  try {
2979
- const response = await axios11__default.default.post(
3047
+ const response = await axios5__default.default.post(
2980
3048
  `${this.baseUrl}/${modelToUse}`,
2981
3049
  {
2982
3050
  inputs: texts,
@@ -2999,7 +3067,7 @@ var HuggingFaceEmbeddingProvider = class {
2999
3067
  dimensions
3000
3068
  };
3001
3069
  } catch (error) {
3002
- if (axios11__default.default.isAxiosError(error)) {
3070
+ if (axios5__default.default.isAxiosError(error)) {
3003
3071
  const status = error.response?.status;
3004
3072
  const message = error.response?.data?.error || error.message;
3005
3073
  let messageText;
@@ -3048,7 +3116,7 @@ var VoyageEmbeddingProvider = class {
3048
3116
  const modelToUse = model || this.defaultModel;
3049
3117
  return retryWithBackoff2(async () => {
3050
3118
  try {
3051
- const response = await axios11__default.default.post(
3119
+ const response = await axios5__default.default.post(
3052
3120
  `${this.baseUrl}/embeddings`,
3053
3121
  {
3054
3122
  input: texts,
@@ -3075,7 +3143,7 @@ var VoyageEmbeddingProvider = class {
3075
3143
  } : void 0
3076
3144
  };
3077
3145
  } catch (error) {
3078
- if (axios11__default.default.isAxiosError(error)) {
3146
+ if (axios5__default.default.isAxiosError(error)) {
3079
3147
  const status = error.response?.status;
3080
3148
  const message = error.response?.data?.message || error.message;
3081
3149
  let messageText;
@@ -3112,7 +3180,7 @@ var OllamaEmbeddingProvider = class {
3112
3180
  const modelToUse = model || this.defaultModel;
3113
3181
  return retryWithBackoff2(async () => {
3114
3182
  try {
3115
- const response = await axios11__default.default.post(
3183
+ const response = await axios5__default.default.post(
3116
3184
  `${this.baseUrl}/api/embeddings`,
3117
3185
  {
3118
3186
  model: modelToUse,
@@ -3131,7 +3199,7 @@ var OllamaEmbeddingProvider = class {
3131
3199
  dimensions: embedding.length
3132
3200
  };
3133
3201
  } catch (error) {
3134
- if (axios11__default.default.isAxiosError(error)) {
3202
+ if (axios5__default.default.isAxiosError(error)) {
3135
3203
  const status = error.response?.status;
3136
3204
  const message = error.response?.data?.error || error.message;
3137
3205
  let messageText;
@@ -3524,6 +3592,16 @@ function formatResults(records) {
3524
3592
  });
3525
3593
  }
3526
3594
 
3595
+ // src/data/neo4j/tools/session-owner.ts
3596
+ async function withNeo4jSession(database, operation) {
3597
+ const session = neo4jPool.getSession(database);
3598
+ try {
3599
+ return await operation(session);
3600
+ } finally {
3601
+ await session.close();
3602
+ }
3603
+ }
3604
+
3527
3605
  // src/data/neo4j/tools/neo4j-query.ts
3528
3606
  var logger4 = core.createLogger("agentforge:tools:neo4j:query");
3529
3607
  function createNeo4jQueryTool() {
@@ -3544,8 +3622,7 @@ function createNeo4jQueryTool() {
3544
3622
  ...input.database ? { database: input.database } : {}
3545
3623
  });
3546
3624
  try {
3547
- const session = neo4jPool.getSession(input.database);
3548
- try {
3625
+ return await withNeo4jSession(input.database, async (session) => {
3549
3626
  const result = await session.run(input.cypher, input.parameters || {});
3550
3627
  const formattedResults = formatResults(result.records);
3551
3628
  const duration = Date.now() - startTime;
@@ -3574,9 +3651,7 @@ function createNeo4jQueryTool() {
3574
3651
  }
3575
3652
  }
3576
3653
  };
3577
- } finally {
3578
- await session.close();
3579
- }
3654
+ });
3580
3655
  } catch (error) {
3581
3656
  const duration = Date.now() - startTime;
3582
3657
  const errorMessage = error instanceof Error ? error.message : "Failed to execute query";
@@ -3604,8 +3679,7 @@ function createNeo4jGetSchemaTool() {
3604
3679
  };
3605
3680
  }
3606
3681
  try {
3607
- const session = neo4jPool.getSession(input.database);
3608
- try {
3682
+ return await withNeo4jSession(input.database, async (session) => {
3609
3683
  const labelsResult = await session.run("CALL db.labels()");
3610
3684
  const nodeLabels = labelsResult.records.map((r) => r.get("label"));
3611
3685
  const relTypesResult = await session.run("CALL db.relationshipTypes()");
@@ -3645,9 +3719,7 @@ function createNeo4jGetSchemaTool() {
3645
3719
  totalIndexes: indexes.length
3646
3720
  }
3647
3721
  };
3648
- } finally {
3649
- await session.close();
3650
- }
3722
+ });
3651
3723
  } catch (error) {
3652
3724
  return {
3653
3725
  success: false,
@@ -3726,8 +3798,7 @@ function createNeo4jFindNodesTool() {
3726
3798
  }
3727
3799
  try {
3728
3800
  const safeLabel = validateLabel(input.label);
3729
- const session = neo4jPool.getSession(input.database);
3730
- try {
3801
+ return await withNeo4jSession(input.database, async (session) => {
3731
3802
  let cypher = `MATCH (n:${safeLabel})`;
3732
3803
  let parameters = {};
3733
3804
  if (input.properties && Object.keys(input.properties).length > 0) {
@@ -3749,9 +3820,7 @@ function createNeo4jFindNodesTool() {
3749
3820
  limit: input.limit
3750
3821
  }
3751
3822
  };
3752
- } finally {
3753
- await session.close();
3754
- }
3823
+ });
3755
3824
  } catch (error) {
3756
3825
  return {
3757
3826
  success: false,
@@ -3777,8 +3846,7 @@ function createNeo4jTraverseTool() {
3777
3846
  try {
3778
3847
  const safeDirection = validateDirection(input.direction || "outgoing");
3779
3848
  const safeRelType = input.relationshipType ? validateRelationshipType(input.relationshipType) : null;
3780
- const session = neo4jPool.getSession(input.database);
3781
- try {
3849
+ return await withNeo4jSession(input.database, async (session) => {
3782
3850
  let relPattern = "";
3783
3851
  if (safeDirection === "OUTGOING") {
3784
3852
  relPattern = safeRelType ? `-[r:${safeRelType}*1..${input.maxDepth}]->` : `-[r*1..${input.maxDepth}]->`;
@@ -3815,9 +3883,7 @@ function createNeo4jTraverseTool() {
3815
3883
  maxDepth: input.maxDepth
3816
3884
  }
3817
3885
  };
3818
- } finally {
3819
- await session.close();
3820
- }
3886
+ });
3821
3887
  } catch (error) {
3822
3888
  return {
3823
3889
  success: false,
@@ -3842,8 +3908,7 @@ function createNeo4jVectorSearchTool() {
3842
3908
  };
3843
3909
  }
3844
3910
  try {
3845
- const session = neo4jPool.getSession(input.database);
3846
- try {
3911
+ return await withNeo4jSession(input.database, async (session) => {
3847
3912
  const cypher = `
3848
3913
  CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
3849
3914
  YIELD node, score
@@ -3870,9 +3935,7 @@ function createNeo4jVectorSearchTool() {
3870
3935
  limit: input.limit
3871
3936
  }
3872
3937
  };
3873
- } finally {
3874
- await session.close();
3875
- }
3938
+ });
3876
3939
  } catch (error) {
3877
3940
  const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search";
3878
3941
  let helpText = "";
@@ -3918,8 +3981,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
3918
3981
  });
3919
3982
  try {
3920
3983
  const embeddingResult = await embeddingManager.generateEmbedding(input.queryText, input.model);
3921
- const session = neo4jPool.getSession(input.database);
3922
- try {
3984
+ return await withNeo4jSession(input.database, async (session) => {
3923
3985
  const cypher = `
3924
3986
  CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
3925
3987
  YIELD node, score
@@ -3961,9 +4023,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
3961
4023
  usage: embeddingResult.usage
3962
4024
  }
3963
4025
  };
3964
- } finally {
3965
- await session.close();
3966
- }
4026
+ });
3967
4027
  } catch (error) {
3968
4028
  const duration = Date.now() - startTime;
3969
4029
  const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search with embedding";
@@ -4019,8 +4079,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
4019
4079
  const embeddingResult = await embeddingManager.generateEmbedding(textToEmbed, input.model);
4020
4080
  const safeLabel = validateLabel(input.label);
4021
4081
  const safeEmbeddingProp = validatePropertyKey(input.embeddingProperty || "embedding");
4022
- const session = neo4jPool.getSession(input.database);
4023
- try {
4082
+ return await withNeo4jSession(input.database, async (session) => {
4024
4083
  const allProperties = {
4025
4084
  ...input.properties
4026
4085
  };
@@ -4054,9 +4113,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
4054
4113
  },
4055
4114
  message: `Created node with label '${input.label}' and ${embeddingResult.dimensions}-dimensional embedding`
4056
4115
  };
4057
- } finally {
4058
- await session.close();
4059
- }
4116
+ });
4060
4117
  } catch (error) {
4061
4118
  const errorMessage = error instanceof Error ? error.message : "Failed to create node with embedding";
4062
4119
  let helpText = "";
@@ -10343,49 +10400,57 @@ var fileSearchSchema = zod.z.object({
10343
10400
  recursive: zod.z.boolean().default(true).describe("Search in subdirectories"),
10344
10401
  caseSensitive: zod.z.boolean().default(false).describe("Case-sensitive pattern matching")
10345
10402
  });
10403
+ async function* traverseDirectory(directory, recursive) {
10404
+ const entries = await fs.promises.readdir(directory, { withFileTypes: true });
10405
+ for (const entry of entries) {
10406
+ const fullPath = path__namespace.join(directory, entry.name);
10407
+ const isDirectory = entry.isDirectory();
10408
+ yield {
10409
+ name: entry.name,
10410
+ fullPath,
10411
+ isFile: entry.isFile(),
10412
+ isDirectory
10413
+ };
10414
+ if (recursive && isDirectory) {
10415
+ yield* traverseDirectory(fullPath, true);
10416
+ }
10417
+ }
10418
+ }
10419
+
10420
+ // src/file/directory/tools/directory-list.ts
10346
10421
  function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
10347
10422
  return core.toolBuilder().name("directory-list").description("List all files and directories in a directory. Can optionally include file details and filter by extension.").category(core.ToolCategory.FILE_SYSTEM).tags(["directory", "list", "files", "filesystem"]).schema(directoryListSchema).implementSafe(async (input) => {
10348
10423
  const safePath = await policy.resolvePath(input.path, "directory listing");
10349
10424
  const includeDetails = input.includeDetails ?? defaultIncludeDetails;
10350
- const listFiles = async (dir, recursive2) => {
10351
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
10352
- const files2 = [];
10353
- for (const entry of entries) {
10354
- const fullPath = path__namespace.join(dir, entry.name);
10355
- const relativePath = path__namespace.relative(safePath, fullPath);
10356
- if (input.extension && !entry.name.endsWith(input.extension)) {
10357
- if (!entry.isDirectory() || !recursive2) {
10358
- continue;
10359
- }
10360
- }
10361
- if (includeDetails) {
10362
- const stats = await fs.promises.lstat(fullPath);
10363
- files2.push({
10364
- name: entry.name,
10365
- path: relativePath,
10366
- fullPath,
10367
- isFile: entry.isFile(),
10368
- isDirectory: entry.isDirectory(),
10369
- size: stats.size,
10370
- modified: stats.mtime.toISOString()
10371
- });
10372
- } else {
10373
- files2.push({
10374
- name: entry.name,
10375
- path: relativePath,
10376
- isFile: entry.isFile(),
10377
- isDirectory: entry.isDirectory()
10378
- });
10379
- }
10380
- if (recursive2 && entry.isDirectory()) {
10381
- const subFiles = await listFiles(fullPath, true);
10382
- files2.push(...subFiles);
10425
+ const recursive = input.recursive ?? defaultRecursive;
10426
+ const files = [];
10427
+ for await (const entry of traverseDirectory(safePath, recursive)) {
10428
+ const relativePath = path__namespace.relative(safePath, entry.fullPath);
10429
+ if (input.extension && !entry.name.endsWith(input.extension)) {
10430
+ if (!entry.isDirectory || !recursive) {
10431
+ continue;
10383
10432
  }
10384
10433
  }
10385
- return files2;
10386
- };
10387
- const recursive = input.recursive ?? defaultRecursive;
10388
- const files = await listFiles(safePath, recursive);
10434
+ if (includeDetails) {
10435
+ const stats = await fs.promises.lstat(entry.fullPath);
10436
+ files.push({
10437
+ name: entry.name,
10438
+ path: relativePath,
10439
+ fullPath: entry.fullPath,
10440
+ isFile: entry.isFile,
10441
+ isDirectory: entry.isDirectory,
10442
+ size: stats.size,
10443
+ modified: stats.mtime.toISOString()
10444
+ });
10445
+ } else {
10446
+ files.push({
10447
+ name: entry.name,
10448
+ path: relativePath,
10449
+ isFile: entry.isFile,
10450
+ isDirectory: entry.isDirectory
10451
+ });
10452
+ }
10453
+ }
10389
10454
  const result = {
10390
10455
  path: input.path,
10391
10456
  files,
@@ -10421,24 +10486,14 @@ function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = fa
10421
10486
  const recursive = input.recursive ?? defaultRecursive;
10422
10487
  const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
10423
10488
  const safeDirectory = await policy.resolvePath(input.directory, "file search");
10424
- const searchFiles = async (dir) => {
10425
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
10426
- const matches2 = [];
10427
- const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
10428
- const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
10429
- for (const entry of entries) {
10430
- const fullPath = path__namespace.join(dir, entry.name);
10431
- if (entry.isFile() && regex.test(entry.name)) {
10432
- matches2.push(fullPath);
10433
- }
10434
- if (recursive && entry.isDirectory()) {
10435
- const subMatches = await searchFiles(fullPath);
10436
- matches2.push(...subMatches);
10437
- }
10489
+ const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
10490
+ const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
10491
+ const matches = [];
10492
+ for await (const entry of traverseDirectory(safeDirectory, recursive)) {
10493
+ if (entry.isFile && regex.test(entry.name)) {
10494
+ matches.push(entry.fullPath);
10438
10495
  }
10439
- return matches2;
10440
- };
10441
- const matches = await searchFiles(safeDirectory);
10496
+ }
10442
10497
  return {
10443
10498
  directory: input.directory,
10444
10499
  pattern: input.pattern,
@@ -11400,11 +11455,11 @@ var AskHumanInputSchema = zod.z.object({
11400
11455
  });
11401
11456
  var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
11402
11457
  var logger19 = core.createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
11403
- function isRecord3(value) {
11458
+ function isRecord4(value) {
11404
11459
  return typeof value === "object" && value !== null;
11405
11460
  }
11406
11461
  function resolveInterrupt(module) {
11407
- if (!isRecord3(module)) {
11462
+ if (!isRecord4(module)) {
11408
11463
  return void 0;
11409
11464
  }
11410
11465
  const candidate = module.interrupt;