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