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