@agentforge/tools 0.18.4 → 0.18.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -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}`);
@@ -740,7 +740,7 @@ var DuckDuckGoProvider = class {
740
740
  async search(query, maxResults, timeout = DEFAULT_TIMEOUT) {
741
741
  try {
742
742
  return await retryWithBackoff(async () => {
743
- const response = await axios11__default.default.get("https://api.duckduckgo.com/", {
743
+ const response = await axios5__default.default.get("https://api.duckduckgo.com/", {
744
744
  params: {
745
745
  q: query,
746
746
  format: "json"
@@ -841,7 +841,7 @@ var SerperProvider = class {
841
841
  }
842
842
  try {
843
843
  return await retryWithBackoff(async () => {
844
- const response = await axios11__default.default.post(
844
+ const response = await axios5__default.default.post(
845
845
  "https://google.serper.dev/search",
846
846
  {
847
847
  q: query,
@@ -977,47 +977,33 @@ var webSearch = core.toolBuilder().name("web-search").description(
977
977
  };
978
978
  }
979
979
  }).build();
980
- function createGetConfiguredSlackClient(token, botName = "AgentForge Bot", botIcon = ":robot_face:") {
981
- let configuredClient = null;
982
- return function getConfiguredSlackClient() {
983
- if (!configuredClient) {
984
- const slackToken = token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
985
- if (!slackToken) {
986
- throw new Error(
987
- "Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
988
- );
980
+ function createLazySlackClient(resolveToken, config, missingTokenError) {
981
+ let client = null;
982
+ return () => {
983
+ const token = resolveToken();
984
+ if (!client) {
985
+ if (!token) {
986
+ throw new Error(missingTokenError);
989
987
  }
990
- configuredClient = new webApi.WebClient(slackToken);
988
+ client = new webApi.WebClient(token);
991
989
  }
992
- return {
993
- client: configuredClient,
994
- config: {
995
- token: token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN || "",
996
- botName,
997
- botIcon
998
- }
999
- };
990
+ return { client, config: { token: token || "", ...config } };
1000
991
  };
1001
992
  }
1002
- var defaultSlackClient = null;
993
+ function createGetConfiguredSlackClient(token, botName = "AgentForge Bot", botIcon = ":robot_face:") {
994
+ return createLazySlackClient(
995
+ () => token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN,
996
+ { botName, botIcon },
997
+ "Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
998
+ );
999
+ }
1000
+ var getLazyDefaultSlackClient = createLazySlackClient(
1001
+ () => process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN,
1002
+ { botName: "AgentForge Bot", botIcon: ":robot_face:" },
1003
+ "Slack token not configured. Please set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
1004
+ );
1003
1005
  function getDefaultSlackClient() {
1004
- if (!defaultSlackClient) {
1005
- const token = process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
1006
- if (!token) {
1007
- throw new Error(
1008
- "Slack token not configured. Please set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
1009
- );
1010
- }
1011
- defaultSlackClient = new webApi.WebClient(token);
1012
- }
1013
- return {
1014
- client: defaultSlackClient,
1015
- config: {
1016
- token: process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN || "",
1017
- botName: "AgentForge Bot",
1018
- botIcon: ":robot_face:"
1019
- }
1020
- };
1006
+ return getLazyDefaultSlackClient();
1021
1007
  }
1022
1008
  function createSendSlackMessageTool(getSlackClient, logger20) {
1023
1009
  return core.toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(core.ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
@@ -1244,38 +1230,91 @@ function createGetConfiguredAuth(apiKey, email, siteUrl) {
1244
1230
  return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
1245
1231
  };
1246
1232
  }
1247
- function createGetConfiguredAuthHeader(getConfiguredAuth) {
1248
- return function getConfiguredAuthHeader() {
1249
- const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfiguredAuth();
1250
- const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1251
- return `Basic ${auth2}`;
1252
- };
1253
- }
1254
1233
  function getConfig() {
1255
1234
  const ATLASSIAN_API_KEY = process.env.ATLASSIAN_API_KEY || "";
1256
1235
  const ATLASSIAN_EMAIL = process.env.ATLASSIAN_EMAIL || "";
1257
1236
  const ATLASSIAN_SITE_URL = (process.env.ATLASSIAN_SITE_URL || "").replace(/\/$/, "");
1258
1237
  if (!ATLASSIAN_API_KEY || !ATLASSIAN_EMAIL || !ATLASSIAN_SITE_URL) {
1259
- throw new Error("Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env");
1238
+ throw new Error(
1239
+ "Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env"
1240
+ );
1260
1241
  }
1261
1242
  return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
1262
1243
  }
1263
- function getAuthHeader() {
1264
- const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfig();
1265
- const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
1266
- return `Basic ${auth2}`;
1244
+ function isRecord(value) {
1245
+ return typeof value === "object" && value !== null;
1267
1246
  }
1268
- function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1269
- 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({
1270
- query: zod.z.string().describe("Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"),
1271
- limit: zod.z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1272
- })).implement(async ({ query, limit = 10 }) => {
1247
+ function describeError(error) {
1248
+ const errorRecord = isRecord(error) ? error : void 0;
1249
+ const response = isRecord(errorRecord?.response) ? errorRecord.response : void 0;
1250
+ const responseData = isRecord(response?.data) ? response.data : void 0;
1251
+ const providerMessage = typeof responseData?.message === "string" ? responseData.message : void 0;
1252
+ const errorMessage = typeof errorRecord?.message === "string" ? errorRecord.message : void 0;
1253
+ return {
1254
+ message: providerMessage || errorMessage,
1255
+ status: typeof response?.status === "number" ? response.status : void 0
1256
+ };
1257
+ }
1258
+ function authenticatedConfig(auth2, config = {}) {
1259
+ const credentials = Buffer.from(`${auth2.ATLASSIAN_EMAIL}:${auth2.ATLASSIAN_API_KEY}`).toString(
1260
+ "base64"
1261
+ );
1262
+ return {
1263
+ ...config,
1264
+ headers: {
1265
+ ...config.headers,
1266
+ Authorization: `Basic ${credentials}`
1267
+ }
1268
+ };
1269
+ }
1270
+ function createConfluenceRequest(getAuth) {
1271
+ return {
1272
+ async get(path13, config = {}) {
1273
+ const auth2 = getAuth();
1274
+ const response = await axios5__default.default.get(
1275
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1276
+ authenticatedConfig(auth2, config)
1277
+ );
1278
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1279
+ },
1280
+ async post(path13, data, config = {}) {
1281
+ const auth2 = getAuth();
1282
+ const response = await axios5__default.default.post(
1283
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1284
+ data,
1285
+ authenticatedConfig(auth2, config)
1286
+ );
1287
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1288
+ },
1289
+ async put(path13, data, config = {}) {
1290
+ const auth2 = getAuth();
1291
+ const response = await axios5__default.default.put(
1292
+ `${auth2.ATLASSIAN_SITE_URL}${path13}`,
1293
+ data,
1294
+ authenticatedConfig(auth2, config)
1295
+ );
1296
+ return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
1297
+ },
1298
+ describeError
1299
+ };
1300
+ }
1301
+ function createSearchConfluenceTool(request2, logger20) {
1302
+ return core.toolBuilder().name("search-confluence").description(
1303
+ "Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts."
1304
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes(
1305
+ "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."
1306
+ ).suggests(["get-confluence-page"]).schema(
1307
+ zod.z.object({
1308
+ query: zod.z.string().describe(
1309
+ "Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"
1310
+ ),
1311
+ limit: zod.z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
1312
+ })
1313
+ ).implement(async ({ query, limit = 10 }) => {
1273
1314
  logger20.info("search-confluence called", { query, limit });
1274
1315
  try {
1275
- const { ATLASSIAN_SITE_URL } = getAuth();
1276
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
1316
+ const response = await request2.get("/wiki/rest/api/content/search", {
1277
1317
  headers: {
1278
- Authorization: getAuthHeader2(),
1279
1318
  Accept: "application/json"
1280
1319
  },
1281
1320
  params: {
@@ -1284,22 +1323,24 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1284
1323
  expand: "space,version"
1285
1324
  }
1286
1325
  });
1287
- const { ATLASSIAN_SITE_URL: siteUrl } = getAuth();
1288
1326
  const results = response.data.results.map((page) => ({
1289
1327
  id: page.id,
1290
1328
  title: page.title,
1291
1329
  type: page.type,
1292
1330
  space: page.space?.name || "Unknown",
1293
1331
  spaceKey: page.space?.key || "",
1294
- url: `${siteUrl}/wiki${page._links.webui}`,
1332
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1295
1333
  lastModified: page.version?.when || ""
1296
1334
  }));
1297
1335
  if (results.length === 0) {
1298
- logger20.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
1299
- query,
1300
- limit,
1301
- totalSize: response.data.totalSize
1302
- });
1336
+ logger20.warn(
1337
+ "search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry",
1338
+ {
1339
+ query,
1340
+ limit,
1341
+ totalSize: response.data.totalSize
1342
+ }
1343
+ );
1303
1344
  } else {
1304
1345
  logger20.info("search-confluence result", {
1305
1346
  query,
@@ -1316,28 +1357,33 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
1316
1357
  results
1317
1358
  });
1318
1359
  } catch (error) {
1360
+ const description = request2.describeError(error);
1319
1361
  logger20.error("search-confluence error", {
1320
1362
  query,
1321
- error: error.response?.data?.message || error.message,
1322
- status: error.response?.status
1363
+ ...description.message !== void 0 ? { error: description.message } : {},
1364
+ ...description.status !== void 0 ? { status: description.status } : {}
1323
1365
  });
1324
1366
  return JSON.stringify({
1325
1367
  success: false,
1326
- error: error.response?.data?.message || error.message
1368
+ error: description.message
1327
1369
  });
1328
1370
  }
1329
1371
  }).build();
1330
1372
  }
1331
- function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1332
- 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({
1333
- page_id: zod.z.string().describe("The Confluence page ID (from search results)")
1334
- })).implement(async ({ page_id }) => {
1373
+ function createGetConfluencePageTool(request2, logger20) {
1374
+ return core.toolBuilder().name("get-confluence-page").description(
1375
+ "Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata."
1376
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes(
1377
+ "Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results."
1378
+ ).requires(["search-confluence"]).schema(
1379
+ zod.z.object({
1380
+ page_id: zod.z.string().describe("The Confluence page ID (from search results)")
1381
+ })
1382
+ ).implement(async ({ page_id }) => {
1335
1383
  logger20.info("get-confluence-page called", { page_id });
1336
1384
  try {
1337
- const { ATLASSIAN_SITE_URL } = getAuth();
1338
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
1385
+ const response = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1339
1386
  headers: {
1340
- Authorization: getAuthHeader2(),
1341
1387
  Accept: "application/json"
1342
1388
  },
1343
1389
  params: {
@@ -1360,35 +1406,40 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1360
1406
  space: page.space?.name || "Unknown",
1361
1407
  spaceKey: page.space?.key || "",
1362
1408
  content: page.body?.storage?.value || "",
1363
- url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
1409
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1364
1410
  created: page.history?.createdDate || "",
1365
1411
  lastModified: page.version?.when || "",
1366
1412
  version: page.version?.number || 1
1367
1413
  }
1368
1414
  });
1369
1415
  } catch (error) {
1416
+ const description = request2.describeError(error);
1370
1417
  logger20.error("get-confluence-page error", {
1371
1418
  page_id,
1372
- error: error.response?.data?.message || error.message,
1373
- status: error.response?.status
1419
+ ...description.message !== void 0 ? { error: description.message } : {},
1420
+ ...description.status !== void 0 ? { status: description.status } : {}
1374
1421
  });
1375
1422
  return JSON.stringify({
1376
1423
  success: false,
1377
- error: error.response?.data?.message || error.message
1424
+ error: description.message
1378
1425
  });
1379
1426
  }
1380
1427
  }).build();
1381
1428
  }
1382
- function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1383
- 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({
1384
- limit: zod.z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1385
- })).implement(async ({ limit = 25 }) => {
1429
+ function createListConfluenceSpacesTool(request2, logger20) {
1430
+ return core.toolBuilder().name("list-confluence-spaces").description(
1431
+ "List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information."
1432
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes(
1433
+ "Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance')."
1434
+ ).follows(["search-confluence"]).schema(
1435
+ zod.z.object({
1436
+ limit: zod.z.number().optional().describe("Maximum number of spaces to return (default: 25)")
1437
+ })
1438
+ ).implement(async ({ limit = 25 }) => {
1386
1439
  logger20.info("list-confluence-spaces called", { limit });
1387
1440
  try {
1388
- const { ATLASSIAN_SITE_URL } = getAuth();
1389
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
1441
+ const response = await request2.get("/wiki/rest/api/space", {
1390
1442
  headers: {
1391
- Authorization: getAuthHeader2(),
1392
1443
  Accept: "application/json"
1393
1444
  },
1394
1445
  params: {
@@ -1400,7 +1451,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1400
1451
  name: space.name,
1401
1452
  type: space.type,
1402
1453
  description: space.description?.plain?.value || "",
1403
- url: `${ATLASSIAN_SITE_URL}/wiki${space._links.webui}`
1454
+ url: `${response.siteUrl}/wiki${space._links.webui}`
1404
1455
  }));
1405
1456
  logger20.info("list-confluence-spaces result", {
1406
1457
  spaceCount: spaces.length,
@@ -1413,28 +1464,33 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
1413
1464
  spaces
1414
1465
  });
1415
1466
  } catch (error) {
1467
+ const description = request2.describeError(error);
1416
1468
  logger20.error("list-confluence-spaces error", {
1417
- error: error.response?.data?.message || error.message,
1418
- status: error.response?.status
1469
+ ...description.message !== void 0 ? { error: description.message } : {},
1470
+ ...description.status !== void 0 ? { status: description.status } : {}
1419
1471
  });
1420
1472
  return JSON.stringify({
1421
1473
  success: false,
1422
- error: error.response?.data?.message || error.message
1474
+ error: description.message
1423
1475
  });
1424
1476
  }
1425
1477
  }).build();
1426
1478
  }
1427
- function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1428
- 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({
1429
- space_key: zod.z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1430
- limit: zod.z.number().optional().describe("Maximum number of pages to return (default: 25)")
1431
- })).implement(async ({ space_key, limit = 25 }) => {
1479
+ function createGetSpacePagesTool(request2, logger20) {
1480
+ return core.toolBuilder().name("get-space-pages").description(
1481
+ "Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area."
1482
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes(
1483
+ "Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first."
1484
+ ).requires(["list-confluence-spaces"]).schema(
1485
+ zod.z.object({
1486
+ space_key: zod.z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
1487
+ limit: zod.z.number().optional().describe("Maximum number of pages to return (default: 25)")
1488
+ })
1489
+ ).implement(async ({ space_key, limit = 25 }) => {
1432
1490
  logger20.info("get-space-pages called", { space_key, limit });
1433
1491
  try {
1434
- const { ATLASSIAN_SITE_URL } = getAuth();
1435
- const response = await axios11__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
1492
+ const response = await request2.get("/wiki/rest/api/content", {
1436
1493
  headers: {
1437
- Authorization: getAuthHeader2(),
1438
1494
  Accept: "application/json"
1439
1495
  },
1440
1496
  params: {
@@ -1447,14 +1503,17 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1447
1503
  const pages = response.data.results.map((page) => ({
1448
1504
  id: page.id,
1449
1505
  title: page.title,
1450
- url: `${ATLASSIAN_SITE_URL}/wiki${page._links.webui}`,
1506
+ url: `${response.siteUrl}/wiki${page._links.webui}`,
1451
1507
  lastModified: page.version?.when || ""
1452
1508
  }));
1453
1509
  if (pages.length === 0) {
1454
- logger20.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
1455
- space_key,
1456
- limit
1457
- });
1510
+ logger20.warn(
1511
+ "get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry",
1512
+ {
1513
+ space_key,
1514
+ limit
1515
+ }
1516
+ );
1458
1517
  } else {
1459
1518
  logger20.info("get-space-pages result", {
1460
1519
  space_key,
@@ -1470,28 +1529,38 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
1470
1529
  pages
1471
1530
  });
1472
1531
  } catch (error) {
1532
+ const description = request2.describeError(error);
1473
1533
  logger20.error("get-space-pages error", {
1474
1534
  space_key,
1475
- error: error.response?.data?.message || error.message,
1476
- status: error.response?.status
1535
+ ...description.message !== void 0 ? { error: description.message } : {},
1536
+ ...description.status !== void 0 ? { status: description.status } : {}
1477
1537
  });
1478
1538
  return JSON.stringify({
1479
1539
  success: false,
1480
- error: error.response?.data?.message || error.message
1540
+ error: description.message
1481
1541
  });
1482
1542
  }
1483
1543
  }).build();
1484
1544
  }
1485
- function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1486
- 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({
1487
- space_key: zod.z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1488
- title: zod.z.string().describe("The title of the new page"),
1489
- content: zod.z.string().describe("The page content in HTML format (Confluence storage format)"),
1490
- parent_page_id: zod.z.string().optional().describe("Optional parent page ID to create this as a child page")
1491
- })).implement(async ({ space_key, title, content, parent_page_id }) => {
1492
- logger20.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
1545
+ function createCreateConfluencePageTool(request2, logger20) {
1546
+ return core.toolBuilder().name("create-confluence-page").description(
1547
+ "Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format)."
1548
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes(
1549
+ "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."
1550
+ ).requires(["list-confluence-spaces"]).schema(
1551
+ zod.z.object({
1552
+ space_key: zod.z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
1553
+ title: zod.z.string().describe("The title of the new page"),
1554
+ content: zod.z.string().describe("The page content in HTML format (Confluence storage format)"),
1555
+ parent_page_id: zod.z.string().optional().describe("Optional parent page ID to create this as a child page")
1556
+ })
1557
+ ).implement(async ({ space_key, title, content, parent_page_id }) => {
1558
+ logger20.info("create-confluence-page called", {
1559
+ space_key,
1560
+ title,
1561
+ hasParent: !!parent_page_id
1562
+ });
1493
1563
  try {
1494
- const { ATLASSIAN_SITE_URL } = getAuth();
1495
1564
  const pageData = {
1496
1565
  type: "page",
1497
1566
  title,
@@ -1506,16 +1575,11 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1506
1575
  if (parent_page_id) {
1507
1576
  pageData.ancestors = [{ id: parent_page_id }];
1508
1577
  }
1509
- const response = await axios11__default.default.post(
1510
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content`,
1511
- pageData,
1512
- {
1513
- headers: {
1514
- Authorization: getAuthHeader2(),
1515
- "Content-Type": "application/json"
1516
- }
1578
+ const response = await request2.post("/wiki/rest/api/content", pageData, {
1579
+ headers: {
1580
+ "Content-Type": "application/json"
1517
1581
  }
1518
- );
1582
+ });
1519
1583
  logger20.info("create-confluence-page result", {
1520
1584
  page_id: response.data.id,
1521
1585
  title: response.data.title,
@@ -1527,45 +1591,45 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1527
1591
  id: response.data.id,
1528
1592
  title: response.data.title,
1529
1593
  space: space_key,
1530
- url: `${ATLASSIAN_SITE_URL}/wiki${response.data._links.webui}`,
1594
+ url: `${response.siteUrl}/wiki${response.data._links.webui}`,
1531
1595
  version: response.data.version?.number || 1
1532
1596
  }
1533
1597
  });
1534
1598
  } catch (error) {
1599
+ const description = request2.describeError(error);
1535
1600
  logger20.error("create-confluence-page error", {
1536
1601
  space_key,
1537
1602
  title,
1538
- error: error.response?.data?.message || error.message,
1539
- status: error.response?.status
1603
+ ...description.message !== void 0 ? { error: description.message } : {},
1604
+ ...description.status !== void 0 ? { status: description.status } : {}
1540
1605
  });
1541
1606
  return JSON.stringify({
1542
1607
  success: false,
1543
- error: error.response?.data?.message || error.message
1608
+ error: description.message
1544
1609
  });
1545
1610
  }
1546
1611
  }).build();
1547
1612
  }
1548
- function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1549
- 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({
1550
- page_id: zod.z.string().describe("The ID of the page to update"),
1551
- title: zod.z.string().describe("The new title for the page"),
1552
- content: zod.z.string().describe("The new content in HTML format (Confluence storage format)")
1553
- })).implement(async ({ page_id, title, content }) => {
1613
+ function createUpdateConfluencePageTool(request2, logger20) {
1614
+ return core.toolBuilder().name("update-confluence-page").description(
1615
+ "Update an existing Confluence page's content. Requires page ID, new title, and new content."
1616
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes(
1617
+ "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."
1618
+ ).requires(["get-confluence-page"]).schema(
1619
+ zod.z.object({
1620
+ page_id: zod.z.string().describe("The ID of the page to update"),
1621
+ title: zod.z.string().describe("The new title for the page"),
1622
+ content: zod.z.string().describe("The new content in HTML format (Confluence storage format)")
1623
+ })
1624
+ ).implement(async ({ page_id, title, content }) => {
1554
1625
  logger20.info("update-confluence-page called", { page_id, title });
1555
1626
  try {
1556
- const { ATLASSIAN_SITE_URL } = getAuth();
1557
- const getResponse = await axios11__default.default.get(
1558
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1559
- {
1560
- headers: {
1561
- Authorization: getAuthHeader2()
1562
- },
1563
- params: { expand: "version" }
1564
- }
1565
- );
1627
+ const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1628
+ params: { expand: "version" }
1629
+ });
1566
1630
  const currentVersion = getResponse.data.version.number;
1567
- const updateResponse = await axios11__default.default.put(
1568
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1631
+ const updateResponse = await request2.put(
1632
+ `/wiki/rest/api/content/${page_id}`,
1569
1633
  {
1570
1634
  type: "page",
1571
1635
  title,
@@ -1579,7 +1643,6 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1579
1643
  },
1580
1644
  {
1581
1645
  headers: {
1582
- Authorization: getAuthHeader2(),
1583
1646
  "Content-Type": "application/json"
1584
1647
  }
1585
1648
  }
@@ -1595,49 +1658,49 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1595
1658
  page: {
1596
1659
  id: updateResponse.data.id,
1597
1660
  title: updateResponse.data.title,
1598
- url: `${ATLASSIAN_SITE_URL}/wiki${updateResponse.data._links.webui}`,
1661
+ url: `${updateResponse.siteUrl}/wiki${updateResponse.data._links.webui}`,
1599
1662
  version: updateResponse.data.version.number,
1600
1663
  previousVersion: currentVersion
1601
1664
  }
1602
1665
  });
1603
1666
  } catch (error) {
1667
+ const description = request2.describeError(error);
1604
1668
  logger20.error("update-confluence-page error", {
1605
1669
  page_id,
1606
1670
  title,
1607
- error: error.response?.data?.message || error.message,
1608
- status: error.response?.status
1671
+ ...description.message !== void 0 ? { error: description.message } : {},
1672
+ ...description.status !== void 0 ? { status: description.status } : {}
1609
1673
  });
1610
1674
  return JSON.stringify({
1611
1675
  success: false,
1612
- error: error.response?.data?.message || error.message
1676
+ error: description.message
1613
1677
  });
1614
1678
  }
1615
1679
  }).build();
1616
1680
  }
1617
- function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1618
- 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({
1619
- page_id: zod.z.string().describe("The ID of the page to archive"),
1620
- reason: zod.z.string().optional().describe("Optional reason for archiving (for audit trail)")
1621
- })).implement(async ({ page_id, reason }) => {
1681
+ function createArchiveConfluencePageTool(request2, logger20) {
1682
+ return core.toolBuilder().name("archive-confluence-page").description(
1683
+ "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."
1684
+ ).category(core.ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes(
1685
+ "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."
1686
+ ).conflicts(["create-confluence-page"]).schema(
1687
+ zod.z.object({
1688
+ page_id: zod.z.string().describe("The ID of the page to archive"),
1689
+ reason: zod.z.string().optional().describe("Optional reason for archiving (for audit trail)")
1690
+ })
1691
+ ).implement(async ({ page_id, reason }) => {
1622
1692
  logger20.info("archive-confluence-page called", {
1623
1693
  page_id,
1624
1694
  ...reason ? { reason } : {}
1625
1695
  });
1626
1696
  try {
1627
- const { ATLASSIAN_SITE_URL } = getAuth();
1628
- const getResponse = await axios11__default.default.get(
1629
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1630
- {
1631
- headers: {
1632
- Authorization: getAuthHeader2()
1633
- },
1634
- params: { expand: "version,body.storage,space" }
1635
- }
1636
- );
1697
+ const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
1698
+ params: { expand: "version,body.storage,space" }
1699
+ });
1637
1700
  const currentVersion = getResponse.data.version.number;
1638
1701
  const pageData = getResponse.data;
1639
- await axios11__default.default.put(
1640
- `${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`,
1702
+ await request2.put(
1703
+ `/wiki/rest/api/content/${page_id}`,
1641
1704
  {
1642
1705
  version: { number: currentVersion + 1 },
1643
1706
  title: pageData.title,
@@ -1648,7 +1711,6 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1648
1711
  },
1649
1712
  {
1650
1713
  headers: {
1651
- Authorization: getAuthHeader2(),
1652
1714
  "Content-Type": "application/json"
1653
1715
  }
1654
1716
  }
@@ -1671,14 +1733,15 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1671
1733
  }
1672
1734
  });
1673
1735
  } catch (error) {
1736
+ const description = request2.describeError(error);
1674
1737
  logger20.error("archive-confluence-page error", {
1675
1738
  page_id,
1676
- error: error.response?.data?.message || error.message,
1677
- status: error.response?.status
1739
+ ...description.message !== void 0 ? { error: description.message } : {},
1740
+ ...description.status !== void 0 ? { status: description.status } : {}
1678
1741
  });
1679
1742
  return JSON.stringify({
1680
1743
  success: false,
1681
- error: error.response?.data?.message || error.message
1744
+ error: description.message
1682
1745
  });
1683
1746
  }
1684
1747
  }).build();
@@ -1687,13 +1750,14 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
1687
1750
  // src/web/confluence/index.ts
1688
1751
  var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
1689
1752
  var logger2 = core.createLogger("[tools:confluence]", { level: logLevel2 });
1690
- var searchConfluence = createSearchConfluenceTool(getConfig, getAuthHeader, logger2);
1691
- var getConfluencePage = createGetConfluencePageTool(getConfig, getAuthHeader, logger2);
1692
- var listConfluenceSpaces = createListConfluenceSpacesTool(getConfig, getAuthHeader, logger2);
1693
- var getSpacePages = createGetSpacePagesTool(getConfig, getAuthHeader, logger2);
1694
- var createConfluencePage = createCreateConfluencePageTool(getConfig, getAuthHeader, logger2);
1695
- var updateConfluencePage = createUpdateConfluencePageTool(getConfig, getAuthHeader, logger2);
1696
- var archiveConfluencePage = createArchiveConfluencePageTool(getConfig, getAuthHeader, logger2);
1753
+ var request = createConfluenceRequest(getConfig);
1754
+ var searchConfluence = createSearchConfluenceTool(request, logger2);
1755
+ var getConfluencePage = createGetConfluencePageTool(request, logger2);
1756
+ var listConfluenceSpaces = createListConfluenceSpacesTool(request, logger2);
1757
+ var getSpacePages = createGetSpacePagesTool(request, logger2);
1758
+ var createConfluencePage = createCreateConfluencePageTool(request, logger2);
1759
+ var updateConfluencePage = createUpdateConfluencePageTool(request, logger2);
1760
+ var archiveConfluencePage = createArchiveConfluencePageTool(request, logger2);
1697
1761
  var confluenceTools = [
1698
1762
  // Read tools
1699
1763
  searchConfluence,
@@ -1706,22 +1770,17 @@ var confluenceTools = [
1706
1770
  archiveConfluencePage
1707
1771
  ];
1708
1772
  function createConfluenceTools(config = {}) {
1709
- const {
1710
- apiKey,
1711
- email,
1712
- siteUrl,
1713
- logLevel: customLogLevel
1714
- } = config;
1773
+ const { apiKey, email, siteUrl, logLevel: customLogLevel } = config;
1715
1774
  const getConfiguredAuth = createGetConfiguredAuth(apiKey, email, siteUrl);
1716
- const getConfiguredAuthHeader = createGetConfiguredAuthHeader(getConfiguredAuth);
1775
+ const request2 = createConfluenceRequest(getConfiguredAuth);
1717
1776
  const toolLogger = customLogLevel ? core.createLogger("tools:confluence", { level: customLogLevel }) : logger2;
1718
- const searchConfluence2 = createSearchConfluenceTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1719
- const getConfluencePage2 = createGetConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1720
- const listConfluenceSpaces2 = createListConfluenceSpacesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1721
- const getSpacePages2 = createGetSpacePagesTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1722
- const createConfluencePage2 = createCreateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1723
- const updateConfluencePage2 = createUpdateConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1724
- const archiveConfluencePage2 = createArchiveConfluencePageTool(getConfiguredAuth, getConfiguredAuthHeader, toolLogger);
1777
+ const searchConfluence2 = createSearchConfluenceTool(request2, toolLogger);
1778
+ const getConfluencePage2 = createGetConfluencePageTool(request2, toolLogger);
1779
+ const listConfluenceSpaces2 = createListConfluenceSpacesTool(request2, toolLogger);
1780
+ const getSpacePages2 = createGetSpacePagesTool(request2, toolLogger);
1781
+ const createConfluencePage2 = createCreateConfluencePageTool(request2, toolLogger);
1782
+ const updateConfluencePage2 = createUpdateConfluencePageTool(request2, toolLogger);
1783
+ const archiveConfluencePage2 = createArchiveConfluencePageTool(request2, toolLogger);
1725
1784
  return {
1726
1785
  searchConfluence: searchConfluence2,
1727
1786
  getConfluencePage: getConfluencePage2,
@@ -1912,14 +1971,14 @@ function createJsonStringifyTool(defaultIndent = 2, defaultPretty = false) {
1912
1971
  };
1913
1972
  }).build();
1914
1973
  }
1915
- function isRecord(value) {
1974
+ function isRecord2(value) {
1916
1975
  return typeof value === "object" && value !== null && !Array.isArray(value);
1917
1976
  }
1918
1977
  function getPathValue(current, part) {
1919
1978
  const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1920
1979
  if (arrayMatch) {
1921
1980
  const [, key, index] = arrayMatch;
1922
- if (!isRecord(current)) {
1981
+ if (!isRecord2(current)) {
1923
1982
  return void 0;
1924
1983
  }
1925
1984
  const candidate = current[key];
@@ -1928,7 +1987,7 @@ function getPathValue(current, part) {
1928
1987
  }
1929
1988
  return candidate[parseInt(index, 10)];
1930
1989
  }
1931
- if (!isRecord(current)) {
1990
+ if (!isRecord2(current)) {
1932
1991
  return void 0;
1933
1992
  }
1934
1993
  return current[part];
@@ -2584,7 +2643,7 @@ async function initializeFromEnv() {
2584
2643
  // src/data/neo4j/embeddings/utils.ts
2585
2644
  function withProviderErrorMetadata(error, message) {
2586
2645
  const wrappedError = new Error(message);
2587
- if (!isRecord2(error)) return wrappedError;
2646
+ if (!isRecord3(error)) return wrappedError;
2588
2647
  if (typeof error.code === "string") wrappedError.code = error.code;
2589
2648
  if (error.response !== void 0) wrappedError.response = error.response;
2590
2649
  return wrappedError;
@@ -2597,12 +2656,12 @@ var DEFAULT_RETRY_CONFIG2 = {
2597
2656
  // 10 seconds
2598
2657
  backoffMultiplier: 2
2599
2658
  };
2600
- function isRecord2(value) {
2659
+ function isRecord3(value) {
2601
2660
  return typeof value === "object" && value !== null;
2602
2661
  }
2603
2662
  function isRetryableError2(error) {
2604
- if (!isRecord2(error)) return false;
2605
- const response = isRecord2(error.response) ? error.response : void 0;
2663
+ if (!isRecord3(error)) return false;
2664
+ const response = isRecord3(error.response) ? error.response : void 0;
2606
2665
  const status = typeof response?.status === "number" ? response.status : void 0;
2607
2666
  const code = typeof error.code === "string" ? error.code : void 0;
2608
2667
  const message = typeof error.message === "string" ? error.message : void 0;
@@ -2728,7 +2787,7 @@ var OpenAIEmbeddingProvider = class {
2728
2787
  const modelToUse = model || this.defaultModel;
2729
2788
  return retryWithBackoff2(async () => {
2730
2789
  try {
2731
- const response = await axios11__default.default.post(
2790
+ const response = await axios5__default.default.post(
2732
2791
  `${this.baseURL}/embeddings`,
2733
2792
  {
2734
2793
  input: text,
@@ -2758,7 +2817,7 @@ var OpenAIEmbeddingProvider = class {
2758
2817
  };
2759
2818
  } catch (error) {
2760
2819
  let message;
2761
- const response = axios11__default.default.isAxiosError(error) ? error.response : void 0;
2820
+ const response = axios5__default.default.isAxiosError(error) ? error.response : void 0;
2762
2821
  if (response?.status === 401) {
2763
2822
  message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
2764
2823
  } else if (response?.status === 429) {
@@ -2785,7 +2844,7 @@ var OpenAIEmbeddingProvider = class {
2785
2844
  const modelToUse = model || this.defaultModel;
2786
2845
  return retryWithBackoff2(async () => {
2787
2846
  try {
2788
- const response = await axios11__default.default.post(
2847
+ const response = await axios5__default.default.post(
2789
2848
  `${this.baseURL}/embeddings`,
2790
2849
  {
2791
2850
  input: texts,
@@ -2816,7 +2875,7 @@ var OpenAIEmbeddingProvider = class {
2816
2875
  };
2817
2876
  } catch (error) {
2818
2877
  let message;
2819
- const response = axios11__default.default.isAxiosError(error) ? error.response : void 0;
2878
+ const response = axios5__default.default.isAxiosError(error) ? error.response : void 0;
2820
2879
  if (response?.status === 401) {
2821
2880
  message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
2822
2881
  } else if (response?.status === 429) {
@@ -2858,7 +2917,7 @@ var CohereEmbeddingProvider = class {
2858
2917
  const modelToUse = model || this.defaultModel;
2859
2918
  return retryWithBackoff2(async () => {
2860
2919
  try {
2861
- const response = await axios11__default.default.post(
2920
+ const response = await axios5__default.default.post(
2862
2921
  `${this.baseUrl}/embed`,
2863
2922
  {
2864
2923
  texts,
@@ -2886,7 +2945,7 @@ var CohereEmbeddingProvider = class {
2886
2945
  } : void 0
2887
2946
  };
2888
2947
  } catch (error) {
2889
- if (axios11__default.default.isAxiosError(error)) {
2948
+ if (axios5__default.default.isAxiosError(error)) {
2890
2949
  const status = error.response?.status;
2891
2950
  const providerMessage = error.response?.data?.message || error.message;
2892
2951
  let message;
@@ -2921,80 +2980,54 @@ var HuggingFaceEmbeddingProvider = class {
2921
2980
  return !!this.apiKey;
2922
2981
  }
2923
2982
  async generateEmbedding(text, model) {
2924
- const modelToUse = model || this.defaultModel;
2925
- return retryWithBackoff2(async () => {
2926
- try {
2927
- const response = await axios11__default.default.post(
2928
- `${this.baseUrl}/${modelToUse}`,
2929
- {
2930
- inputs: text,
2931
- options: {
2932
- wait_for_model: true
2933
- }
2934
- },
2935
- {
2936
- headers: {
2937
- "Authorization": `Bearer ${this.apiKey}`,
2938
- "Content-Type": "application/json"
2939
- }
2940
- }
2941
- );
2942
- const embedding = Array.isArray(response.data) ? response.data : response.data[0];
2943
- return {
2944
- embedding,
2945
- model: modelToUse,
2946
- dimensions: embedding.length
2947
- };
2948
- } catch (error) {
2949
- if (axios11__default.default.isAxiosError(error)) {
2950
- const status = error.response?.status;
2951
- const message = error.response?.data?.error || error.message;
2952
- let messageText;
2953
- if (status === 401) {
2954
- messageText = `HuggingFace API authentication failed. Please check your HUGGINGFACE_API_KEY. ${message}`;
2955
- } else if (status === 429) {
2956
- messageText = `HuggingFace API rate limit exceeded. ${message}`;
2957
- } else if (status === 400) {
2958
- messageText = `HuggingFace API request invalid: ${message}`;
2959
- } else if (status === 503) {
2960
- messageText = `HuggingFace model is loading. Please retry in a moment. ${message}`;
2961
- } else {
2962
- messageText = `HuggingFace API error (${status}): ${message}`;
2963
- }
2964
- throw withProviderErrorMetadata(error, messageText);
2965
- }
2966
- throw error;
2967
- }
2968
- });
2983
+ const { data, model: modelToUse } = await this.requestEmbeddings(
2984
+ text,
2985
+ model
2986
+ );
2987
+ const embedding = Array.isArray(data) ? data : data[0];
2988
+ return {
2989
+ embedding,
2990
+ model: modelToUse,
2991
+ dimensions: embedding.length
2992
+ };
2969
2993
  }
2970
2994
  async generateBatchEmbeddings(texts, model) {
2995
+ const { data: embeddings, model: modelToUse } = await this.requestEmbeddings(
2996
+ texts,
2997
+ model
2998
+ );
2999
+ const dimensions = embeddings[0]?.length || 0;
3000
+ return {
3001
+ embeddings,
3002
+ model: modelToUse,
3003
+ dimensions
3004
+ };
3005
+ }
3006
+ async requestEmbeddings(inputs, model) {
2971
3007
  const modelToUse = model || this.defaultModel;
2972
3008
  return retryWithBackoff2(async () => {
2973
3009
  try {
2974
- const response = await axios11__default.default.post(
3010
+ const response = await axios5__default.default.post(
2975
3011
  `${this.baseUrl}/${modelToUse}`,
2976
3012
  {
2977
- inputs: texts,
3013
+ inputs,
2978
3014
  options: {
2979
3015
  wait_for_model: true
2980
3016
  }
2981
3017
  },
2982
3018
  {
2983
3019
  headers: {
2984
- "Authorization": `Bearer ${this.apiKey}`,
3020
+ Authorization: `Bearer ${this.apiKey}`,
2985
3021
  "Content-Type": "application/json"
2986
3022
  }
2987
3023
  }
2988
3024
  );
2989
- const embeddings = response.data;
2990
- const dimensions = embeddings[0]?.length || 0;
2991
3025
  return {
2992
- embeddings,
2993
- model: modelToUse,
2994
- dimensions
3026
+ data: response.data,
3027
+ model: modelToUse
2995
3028
  };
2996
3029
  } catch (error) {
2997
- if (axios11__default.default.isAxiosError(error)) {
3030
+ if (axios5__default.default.isAxiosError(error)) {
2998
3031
  const status = error.response?.status;
2999
3032
  const message = error.response?.data?.error || error.message;
3000
3033
  let messageText;
@@ -3043,7 +3076,7 @@ var VoyageEmbeddingProvider = class {
3043
3076
  const modelToUse = model || this.defaultModel;
3044
3077
  return retryWithBackoff2(async () => {
3045
3078
  try {
3046
- const response = await axios11__default.default.post(
3079
+ const response = await axios5__default.default.post(
3047
3080
  `${this.baseUrl}/embeddings`,
3048
3081
  {
3049
3082
  input: texts,
@@ -3070,7 +3103,7 @@ var VoyageEmbeddingProvider = class {
3070
3103
  } : void 0
3071
3104
  };
3072
3105
  } catch (error) {
3073
- if (axios11__default.default.isAxiosError(error)) {
3106
+ if (axios5__default.default.isAxiosError(error)) {
3074
3107
  const status = error.response?.status;
3075
3108
  const message = error.response?.data?.message || error.message;
3076
3109
  let messageText;
@@ -3107,7 +3140,7 @@ var OllamaEmbeddingProvider = class {
3107
3140
  const modelToUse = model || this.defaultModel;
3108
3141
  return retryWithBackoff2(async () => {
3109
3142
  try {
3110
- const response = await axios11__default.default.post(
3143
+ const response = await axios5__default.default.post(
3111
3144
  `${this.baseUrl}/api/embeddings`,
3112
3145
  {
3113
3146
  model: modelToUse,
@@ -3126,7 +3159,7 @@ var OllamaEmbeddingProvider = class {
3126
3159
  dimensions: embedding.length
3127
3160
  };
3128
3161
  } catch (error) {
3129
- if (axios11__default.default.isAxiosError(error)) {
3162
+ if (axios5__default.default.isAxiosError(error)) {
3130
3163
  const status = error.response?.status;
3131
3164
  const message = error.response?.data?.error || error.message;
3132
3165
  let messageText;
@@ -3519,6 +3552,16 @@ function formatResults(records) {
3519
3552
  });
3520
3553
  }
3521
3554
 
3555
+ // src/data/neo4j/tools/session-owner.ts
3556
+ async function withNeo4jSession(database, operation) {
3557
+ const session = neo4jPool.getSession(database);
3558
+ try {
3559
+ return await operation(session);
3560
+ } finally {
3561
+ await session.close();
3562
+ }
3563
+ }
3564
+
3522
3565
  // src/data/neo4j/tools/neo4j-query.ts
3523
3566
  var logger4 = core.createLogger("agentforge:tools:neo4j:query");
3524
3567
  function createNeo4jQueryTool() {
@@ -3539,8 +3582,7 @@ function createNeo4jQueryTool() {
3539
3582
  ...input.database ? { database: input.database } : {}
3540
3583
  });
3541
3584
  try {
3542
- const session = neo4jPool.getSession(input.database);
3543
- try {
3585
+ return await withNeo4jSession(input.database, async (session) => {
3544
3586
  const result = await session.run(input.cypher, input.parameters || {});
3545
3587
  const formattedResults = formatResults(result.records);
3546
3588
  const duration = Date.now() - startTime;
@@ -3569,9 +3611,7 @@ function createNeo4jQueryTool() {
3569
3611
  }
3570
3612
  }
3571
3613
  };
3572
- } finally {
3573
- await session.close();
3574
- }
3614
+ });
3575
3615
  } catch (error) {
3576
3616
  const duration = Date.now() - startTime;
3577
3617
  const errorMessage = error instanceof Error ? error.message : "Failed to execute query";
@@ -3599,8 +3639,7 @@ function createNeo4jGetSchemaTool() {
3599
3639
  };
3600
3640
  }
3601
3641
  try {
3602
- const session = neo4jPool.getSession(input.database);
3603
- try {
3642
+ return await withNeo4jSession(input.database, async (session) => {
3604
3643
  const labelsResult = await session.run("CALL db.labels()");
3605
3644
  const nodeLabels = labelsResult.records.map((r) => r.get("label"));
3606
3645
  const relTypesResult = await session.run("CALL db.relationshipTypes()");
@@ -3640,9 +3679,7 @@ function createNeo4jGetSchemaTool() {
3640
3679
  totalIndexes: indexes.length
3641
3680
  }
3642
3681
  };
3643
- } finally {
3644
- await session.close();
3645
- }
3682
+ });
3646
3683
  } catch (error) {
3647
3684
  return {
3648
3685
  success: false,
@@ -3721,8 +3758,7 @@ function createNeo4jFindNodesTool() {
3721
3758
  }
3722
3759
  try {
3723
3760
  const safeLabel = validateLabel(input.label);
3724
- const session = neo4jPool.getSession(input.database);
3725
- try {
3761
+ return await withNeo4jSession(input.database, async (session) => {
3726
3762
  let cypher = `MATCH (n:${safeLabel})`;
3727
3763
  let parameters = {};
3728
3764
  if (input.properties && Object.keys(input.properties).length > 0) {
@@ -3744,9 +3780,7 @@ function createNeo4jFindNodesTool() {
3744
3780
  limit: input.limit
3745
3781
  }
3746
3782
  };
3747
- } finally {
3748
- await session.close();
3749
- }
3783
+ });
3750
3784
  } catch (error) {
3751
3785
  return {
3752
3786
  success: false,
@@ -3772,8 +3806,7 @@ function createNeo4jTraverseTool() {
3772
3806
  try {
3773
3807
  const safeDirection = validateDirection(input.direction || "outgoing");
3774
3808
  const safeRelType = input.relationshipType ? validateRelationshipType(input.relationshipType) : null;
3775
- const session = neo4jPool.getSession(input.database);
3776
- try {
3809
+ return await withNeo4jSession(input.database, async (session) => {
3777
3810
  let relPattern = "";
3778
3811
  if (safeDirection === "OUTGOING") {
3779
3812
  relPattern = safeRelType ? `-[r:${safeRelType}*1..${input.maxDepth}]->` : `-[r*1..${input.maxDepth}]->`;
@@ -3810,9 +3843,7 @@ function createNeo4jTraverseTool() {
3810
3843
  maxDepth: input.maxDepth
3811
3844
  }
3812
3845
  };
3813
- } finally {
3814
- await session.close();
3815
- }
3846
+ });
3816
3847
  } catch (error) {
3817
3848
  return {
3818
3849
  success: false,
@@ -3837,8 +3868,7 @@ function createNeo4jVectorSearchTool() {
3837
3868
  };
3838
3869
  }
3839
3870
  try {
3840
- const session = neo4jPool.getSession(input.database);
3841
- try {
3871
+ return await withNeo4jSession(input.database, async (session) => {
3842
3872
  const cypher = `
3843
3873
  CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
3844
3874
  YIELD node, score
@@ -3865,9 +3895,7 @@ function createNeo4jVectorSearchTool() {
3865
3895
  limit: input.limit
3866
3896
  }
3867
3897
  };
3868
- } finally {
3869
- await session.close();
3870
- }
3898
+ });
3871
3899
  } catch (error) {
3872
3900
  const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search";
3873
3901
  let helpText = "";
@@ -3913,8 +3941,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
3913
3941
  });
3914
3942
  try {
3915
3943
  const embeddingResult = await embeddingManager.generateEmbedding(input.queryText, input.model);
3916
- const session = neo4jPool.getSession(input.database);
3917
- try {
3944
+ return await withNeo4jSession(input.database, async (session) => {
3918
3945
  const cypher = `
3919
3946
  CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
3920
3947
  YIELD node, score
@@ -3956,9 +3983,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
3956
3983
  usage: embeddingResult.usage
3957
3984
  }
3958
3985
  };
3959
- } finally {
3960
- await session.close();
3961
- }
3986
+ });
3962
3987
  } catch (error) {
3963
3988
  const duration = Date.now() - startTime;
3964
3989
  const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search with embedding";
@@ -4014,8 +4039,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
4014
4039
  const embeddingResult = await embeddingManager.generateEmbedding(textToEmbed, input.model);
4015
4040
  const safeLabel = validateLabel(input.label);
4016
4041
  const safeEmbeddingProp = validatePropertyKey(input.embeddingProperty || "embedding");
4017
- const session = neo4jPool.getSession(input.database);
4018
- try {
4042
+ return await withNeo4jSession(input.database, async (session) => {
4019
4043
  const allProperties = {
4020
4044
  ...input.properties
4021
4045
  };
@@ -4049,9 +4073,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
4049
4073
  },
4050
4074
  message: `Created node with label '${input.label}' and ${embeddingResult.dimensions}-dimensional embedding`
4051
4075
  };
4052
- } finally {
4053
- await session.close();
4054
- }
4076
+ });
4055
4077
  } catch (error) {
4056
4078
  const errorMessage = error instanceof Error ? error.message : "Failed to create node with embedding";
4057
4079
  let helpText = "";
@@ -7139,15 +7161,6 @@ function formatTableName(table) {
7139
7161
  return table.schema ? `${table.schema}.${table.name}` : table.name;
7140
7162
  }
7141
7163
 
7142
- // src/data/relational/schema/type-mapper-normalization.ts
7143
- function normaliseDbType(raw) {
7144
- let type = raw.toLowerCase().trim();
7145
- type = type.replace(/\[\]$/, "");
7146
- type = type.replace(/\([\d,\s]+\)/, "");
7147
- type = type.replace(/\s+unsigned$/, "");
7148
- return type.trim();
7149
- }
7150
-
7151
7164
  // src/data/relational/schema/type-mapper-vendor-maps.ts
7152
7165
  var POSTGRES_TYPE_MAP = {
7153
7166
  smallint: "number",
@@ -7323,6 +7336,13 @@ function getVendorTypeMap(vendor) {
7323
7336
  function usesStringPrecisionFallback(vendor, normalised) {
7324
7337
  return (normalised === "bigint" || normalised === "int8" || normalised === "bigserial") && (vendor === "postgresql" || vendor === "mysql");
7325
7338
  }
7339
+ function normaliseDbType(raw) {
7340
+ let type = raw.toLowerCase().trim();
7341
+ type = type.replace(/\[\]$/, "");
7342
+ type = type.replace(/\([\d,\s]+\)/, "");
7343
+ type = type.replace(/\s+unsigned$/, "");
7344
+ return type.trim();
7345
+ }
7326
7346
  var logger14 = core.createLogger("agentforge:tools:data:relational:schema-diff");
7327
7347
  function diffSchemas(before, after) {
7328
7348
  const tableDiffs = [];
@@ -10338,49 +10358,57 @@ var fileSearchSchema = zod.z.object({
10338
10358
  recursive: zod.z.boolean().default(true).describe("Search in subdirectories"),
10339
10359
  caseSensitive: zod.z.boolean().default(false).describe("Case-sensitive pattern matching")
10340
10360
  });
10361
+ async function* traverseDirectory(directory, recursive) {
10362
+ const entries = await fs.promises.readdir(directory, { withFileTypes: true });
10363
+ for (const entry of entries) {
10364
+ const fullPath = path__namespace.join(directory, entry.name);
10365
+ const isDirectory = entry.isDirectory();
10366
+ yield {
10367
+ name: entry.name,
10368
+ fullPath,
10369
+ isFile: entry.isFile(),
10370
+ isDirectory
10371
+ };
10372
+ if (recursive && isDirectory) {
10373
+ yield* traverseDirectory(fullPath, true);
10374
+ }
10375
+ }
10376
+ }
10377
+
10378
+ // src/file/directory/tools/directory-list.ts
10341
10379
  function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
10342
10380
  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) => {
10343
10381
  const safePath = await policy.resolvePath(input.path, "directory listing");
10344
10382
  const includeDetails = input.includeDetails ?? defaultIncludeDetails;
10345
- const listFiles = async (dir, recursive2) => {
10346
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
10347
- const files2 = [];
10348
- for (const entry of entries) {
10349
- const fullPath = path__namespace.join(dir, entry.name);
10350
- const relativePath = path__namespace.relative(safePath, fullPath);
10351
- if (input.extension && !entry.name.endsWith(input.extension)) {
10352
- if (!entry.isDirectory() || !recursive2) {
10353
- continue;
10354
- }
10355
- }
10356
- if (includeDetails) {
10357
- const stats = await fs.promises.lstat(fullPath);
10358
- files2.push({
10359
- name: entry.name,
10360
- path: relativePath,
10361
- fullPath,
10362
- isFile: entry.isFile(),
10363
- isDirectory: entry.isDirectory(),
10364
- size: stats.size,
10365
- modified: stats.mtime.toISOString()
10366
- });
10367
- } else {
10368
- files2.push({
10369
- name: entry.name,
10370
- path: relativePath,
10371
- isFile: entry.isFile(),
10372
- isDirectory: entry.isDirectory()
10373
- });
10374
- }
10375
- if (recursive2 && entry.isDirectory()) {
10376
- const subFiles = await listFiles(fullPath, true);
10377
- files2.push(...subFiles);
10383
+ const recursive = input.recursive ?? defaultRecursive;
10384
+ const files = [];
10385
+ for await (const entry of traverseDirectory(safePath, recursive)) {
10386
+ const relativePath = path__namespace.relative(safePath, entry.fullPath);
10387
+ if (input.extension && !entry.name.endsWith(input.extension)) {
10388
+ if (!entry.isDirectory || !recursive) {
10389
+ continue;
10378
10390
  }
10379
10391
  }
10380
- return files2;
10381
- };
10382
- const recursive = input.recursive ?? defaultRecursive;
10383
- const files = await listFiles(safePath, recursive);
10392
+ if (includeDetails) {
10393
+ const stats = await fs.promises.lstat(entry.fullPath);
10394
+ files.push({
10395
+ name: entry.name,
10396
+ path: relativePath,
10397
+ fullPath: entry.fullPath,
10398
+ isFile: entry.isFile,
10399
+ isDirectory: entry.isDirectory,
10400
+ size: stats.size,
10401
+ modified: stats.mtime.toISOString()
10402
+ });
10403
+ } else {
10404
+ files.push({
10405
+ name: entry.name,
10406
+ path: relativePath,
10407
+ isFile: entry.isFile,
10408
+ isDirectory: entry.isDirectory
10409
+ });
10410
+ }
10411
+ }
10384
10412
  const result = {
10385
10413
  path: input.path,
10386
10414
  files,
@@ -10416,24 +10444,14 @@ function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = fa
10416
10444
  const recursive = input.recursive ?? defaultRecursive;
10417
10445
  const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
10418
10446
  const safeDirectory = await policy.resolvePath(input.directory, "file search");
10419
- const searchFiles = async (dir) => {
10420
- const entries = await fs.promises.readdir(dir, { withFileTypes: true });
10421
- const matches2 = [];
10422
- const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
10423
- const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
10424
- for (const entry of entries) {
10425
- const fullPath = path__namespace.join(dir, entry.name);
10426
- if (entry.isFile() && regex.test(entry.name)) {
10427
- matches2.push(fullPath);
10428
- }
10429
- if (recursive && entry.isDirectory()) {
10430
- const subMatches = await searchFiles(fullPath);
10431
- matches2.push(...subMatches);
10432
- }
10447
+ const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
10448
+ const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
10449
+ const matches = [];
10450
+ for await (const entry of traverseDirectory(safeDirectory, recursive)) {
10451
+ if (entry.isFile && regex.test(entry.name)) {
10452
+ matches.push(entry.fullPath);
10433
10453
  }
10434
- return matches2;
10435
- };
10436
- const matches = await searchFiles(safeDirectory);
10454
+ }
10437
10455
  return {
10438
10456
  directory: input.directory,
10439
10457
  pattern: input.pattern,
@@ -11395,11 +11413,11 @@ var AskHumanInputSchema = zod.z.object({
11395
11413
  });
11396
11414
  var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
11397
11415
  var logger19 = core.createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
11398
- function isRecord3(value) {
11416
+ function isRecord4(value) {
11399
11417
  return typeof value === "object" && value !== null;
11400
11418
  }
11401
11419
  function resolveInterrupt(module) {
11402
- if (!isRecord3(module)) {
11420
+ if (!isRecord4(module)) {
11403
11421
  return void 0;
11404
11422
  }
11405
11423
  const candidate = module.interrupt;