@agentforge/tools 0.18.4 → 0.18.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +385 -367
- 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 +384 -366
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
|
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
|
|
204
|
+
const response = await axios5(currentConfig);
|
|
205
205
|
if (!isRedirectStatus(response.status)) return response;
|
|
206
206
|
if (effectivePolicy.allowRedirects === false) blockDestination(currentUrl, "redirect");
|
|
207
207
|
if (redirectCount >= maxRedirects) throw new DestinationPolicyError(currentUrl, "redirect", `Maximum redirect count (${maxRedirects}) exceeded for ${currentUrl}`);
|
|
@@ -712,7 +712,7 @@ var DuckDuckGoProvider = class {
|
|
|
712
712
|
async search(query, maxResults, timeout = DEFAULT_TIMEOUT) {
|
|
713
713
|
try {
|
|
714
714
|
return await retryWithBackoff(async () => {
|
|
715
|
-
const response = await
|
|
715
|
+
const response = await axios5.get("https://api.duckduckgo.com/", {
|
|
716
716
|
params: {
|
|
717
717
|
q: query,
|
|
718
718
|
format: "json"
|
|
@@ -813,7 +813,7 @@ var SerperProvider = class {
|
|
|
813
813
|
}
|
|
814
814
|
try {
|
|
815
815
|
return await retryWithBackoff(async () => {
|
|
816
|
-
const response = await
|
|
816
|
+
const response = await axios5.post(
|
|
817
817
|
"https://google.serper.dev/search",
|
|
818
818
|
{
|
|
819
819
|
q: query,
|
|
@@ -949,47 +949,33 @@ var webSearch = toolBuilder().name("web-search").description(
|
|
|
949
949
|
};
|
|
950
950
|
}
|
|
951
951
|
}).build();
|
|
952
|
-
function
|
|
953
|
-
let
|
|
954
|
-
return
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
if (!
|
|
958
|
-
throw new Error(
|
|
959
|
-
"Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
960
|
-
);
|
|
952
|
+
function createLazySlackClient(resolveToken, config, missingTokenError) {
|
|
953
|
+
let client = null;
|
|
954
|
+
return () => {
|
|
955
|
+
const token = resolveToken();
|
|
956
|
+
if (!client) {
|
|
957
|
+
if (!token) {
|
|
958
|
+
throw new Error(missingTokenError);
|
|
961
959
|
}
|
|
962
|
-
|
|
960
|
+
client = new WebClient(token);
|
|
963
961
|
}
|
|
964
|
-
return {
|
|
965
|
-
client: configuredClient,
|
|
966
|
-
config: {
|
|
967
|
-
token: token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN || "",
|
|
968
|
-
botName,
|
|
969
|
-
botIcon
|
|
970
|
-
}
|
|
971
|
-
};
|
|
962
|
+
return { client, config: { token: token || "", ...config } };
|
|
972
963
|
};
|
|
973
964
|
}
|
|
974
|
-
|
|
965
|
+
function createGetConfiguredSlackClient(token, botName = "AgentForge Bot", botIcon = ":robot_face:") {
|
|
966
|
+
return createLazySlackClient(
|
|
967
|
+
() => token || process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN,
|
|
968
|
+
{ botName, botIcon },
|
|
969
|
+
"Slack token not configured. Please provide a token in config or set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
970
|
+
);
|
|
971
|
+
}
|
|
972
|
+
var getLazyDefaultSlackClient = createLazySlackClient(
|
|
973
|
+
() => process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN,
|
|
974
|
+
{ botName: "AgentForge Bot", botIcon: ":robot_face:" },
|
|
975
|
+
"Slack token not configured. Please set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
976
|
+
);
|
|
975
977
|
function getDefaultSlackClient() {
|
|
976
|
-
|
|
977
|
-
const token = process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN;
|
|
978
|
-
if (!token) {
|
|
979
|
-
throw new Error(
|
|
980
|
-
"Slack token not configured. Please set SLACK_USER_TOKEN or SLACK_BOT_TOKEN environment variable."
|
|
981
|
-
);
|
|
982
|
-
}
|
|
983
|
-
defaultSlackClient = new WebClient(token);
|
|
984
|
-
}
|
|
985
|
-
return {
|
|
986
|
-
client: defaultSlackClient,
|
|
987
|
-
config: {
|
|
988
|
-
token: process.env.SLACK_USER_TOKEN || process.env.SLACK_BOT_TOKEN || "",
|
|
989
|
-
botName: "AgentForge Bot",
|
|
990
|
-
botIcon: ":robot_face:"
|
|
991
|
-
}
|
|
992
|
-
};
|
|
978
|
+
return getLazyDefaultSlackClient();
|
|
993
979
|
}
|
|
994
980
|
function createSendSlackMessageTool(getSlackClient, logger20) {
|
|
995
981
|
return toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
|
|
@@ -1216,38 +1202,91 @@ function createGetConfiguredAuth(apiKey, email, siteUrl) {
|
|
|
1216
1202
|
return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
|
|
1217
1203
|
};
|
|
1218
1204
|
}
|
|
1219
|
-
function createGetConfiguredAuthHeader(getConfiguredAuth) {
|
|
1220
|
-
return function getConfiguredAuthHeader() {
|
|
1221
|
-
const { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL } = getConfiguredAuth();
|
|
1222
|
-
const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
|
|
1223
|
-
return `Basic ${auth2}`;
|
|
1224
|
-
};
|
|
1225
|
-
}
|
|
1226
1205
|
function getConfig() {
|
|
1227
1206
|
const ATLASSIAN_API_KEY = process.env.ATLASSIAN_API_KEY || "";
|
|
1228
1207
|
const ATLASSIAN_EMAIL = process.env.ATLASSIAN_EMAIL || "";
|
|
1229
1208
|
const ATLASSIAN_SITE_URL = (process.env.ATLASSIAN_SITE_URL || "").replace(/\/$/, "");
|
|
1230
1209
|
if (!ATLASSIAN_API_KEY || !ATLASSIAN_EMAIL || !ATLASSIAN_SITE_URL) {
|
|
1231
|
-
throw new Error(
|
|
1210
|
+
throw new Error(
|
|
1211
|
+
"Confluence credentials not configured. Set ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, and ATLASSIAN_SITE_URL in .env"
|
|
1212
|
+
);
|
|
1232
1213
|
}
|
|
1233
1214
|
return { ATLASSIAN_API_KEY, ATLASSIAN_EMAIL, ATLASSIAN_SITE_URL };
|
|
1234
1215
|
}
|
|
1235
|
-
function
|
|
1236
|
-
|
|
1237
|
-
const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
|
|
1238
|
-
return `Basic ${auth2}`;
|
|
1216
|
+
function isRecord(value) {
|
|
1217
|
+
return typeof value === "object" && value !== null;
|
|
1239
1218
|
}
|
|
1240
|
-
function
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1219
|
+
function describeError(error) {
|
|
1220
|
+
const errorRecord = isRecord(error) ? error : void 0;
|
|
1221
|
+
const response = isRecord(errorRecord?.response) ? errorRecord.response : void 0;
|
|
1222
|
+
const responseData = isRecord(response?.data) ? response.data : void 0;
|
|
1223
|
+
const providerMessage = typeof responseData?.message === "string" ? responseData.message : void 0;
|
|
1224
|
+
const errorMessage = typeof errorRecord?.message === "string" ? errorRecord.message : void 0;
|
|
1225
|
+
return {
|
|
1226
|
+
message: providerMessage || errorMessage,
|
|
1227
|
+
status: typeof response?.status === "number" ? response.status : void 0
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
function authenticatedConfig(auth2, config = {}) {
|
|
1231
|
+
const credentials = Buffer.from(`${auth2.ATLASSIAN_EMAIL}:${auth2.ATLASSIAN_API_KEY}`).toString(
|
|
1232
|
+
"base64"
|
|
1233
|
+
);
|
|
1234
|
+
return {
|
|
1235
|
+
...config,
|
|
1236
|
+
headers: {
|
|
1237
|
+
...config.headers,
|
|
1238
|
+
Authorization: `Basic ${credentials}`
|
|
1239
|
+
}
|
|
1240
|
+
};
|
|
1241
|
+
}
|
|
1242
|
+
function createConfluenceRequest(getAuth) {
|
|
1243
|
+
return {
|
|
1244
|
+
async get(path13, config = {}) {
|
|
1245
|
+
const auth2 = getAuth();
|
|
1246
|
+
const response = await axios5.get(
|
|
1247
|
+
`${auth2.ATLASSIAN_SITE_URL}${path13}`,
|
|
1248
|
+
authenticatedConfig(auth2, config)
|
|
1249
|
+
);
|
|
1250
|
+
return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
|
|
1251
|
+
},
|
|
1252
|
+
async post(path13, data, config = {}) {
|
|
1253
|
+
const auth2 = getAuth();
|
|
1254
|
+
const response = await axios5.post(
|
|
1255
|
+
`${auth2.ATLASSIAN_SITE_URL}${path13}`,
|
|
1256
|
+
data,
|
|
1257
|
+
authenticatedConfig(auth2, config)
|
|
1258
|
+
);
|
|
1259
|
+
return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
|
|
1260
|
+
},
|
|
1261
|
+
async put(path13, data, config = {}) {
|
|
1262
|
+
const auth2 = getAuth();
|
|
1263
|
+
const response = await axios5.put(
|
|
1264
|
+
`${auth2.ATLASSIAN_SITE_URL}${path13}`,
|
|
1265
|
+
data,
|
|
1266
|
+
authenticatedConfig(auth2, config)
|
|
1267
|
+
);
|
|
1268
|
+
return { data: response.data, siteUrl: auth2.ATLASSIAN_SITE_URL };
|
|
1269
|
+
},
|
|
1270
|
+
describeError
|
|
1271
|
+
};
|
|
1272
|
+
}
|
|
1273
|
+
function createSearchConfluenceTool(request2, logger20) {
|
|
1274
|
+
return toolBuilder().name("search-confluence").description(
|
|
1275
|
+
"Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts."
|
|
1276
|
+
).category(ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes(
|
|
1277
|
+
"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."
|
|
1278
|
+
).suggests(["get-confluence-page"]).schema(
|
|
1279
|
+
z.object({
|
|
1280
|
+
query: z.string().describe(
|
|
1281
|
+
"Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"
|
|
1282
|
+
),
|
|
1283
|
+
limit: z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
|
|
1284
|
+
})
|
|
1285
|
+
).implement(async ({ query, limit = 10 }) => {
|
|
1245
1286
|
logger20.info("search-confluence called", { query, limit });
|
|
1246
1287
|
try {
|
|
1247
|
-
const
|
|
1248
|
-
const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
|
|
1288
|
+
const response = await request2.get("/wiki/rest/api/content/search", {
|
|
1249
1289
|
headers: {
|
|
1250
|
-
Authorization: getAuthHeader2(),
|
|
1251
1290
|
Accept: "application/json"
|
|
1252
1291
|
},
|
|
1253
1292
|
params: {
|
|
@@ -1256,22 +1295,24 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1256
1295
|
expand: "space,version"
|
|
1257
1296
|
}
|
|
1258
1297
|
});
|
|
1259
|
-
const { ATLASSIAN_SITE_URL: siteUrl } = getAuth();
|
|
1260
1298
|
const results = response.data.results.map((page) => ({
|
|
1261
1299
|
id: page.id,
|
|
1262
1300
|
title: page.title,
|
|
1263
1301
|
type: page.type,
|
|
1264
1302
|
space: page.space?.name || "Unknown",
|
|
1265
1303
|
spaceKey: page.space?.key || "",
|
|
1266
|
-
url: `${siteUrl}/wiki${page._links.webui}`,
|
|
1304
|
+
url: `${response.siteUrl}/wiki${page._links.webui}`,
|
|
1267
1305
|
lastModified: page.version?.when || ""
|
|
1268
1306
|
}));
|
|
1269
1307
|
if (results.length === 0) {
|
|
1270
|
-
logger20.warn(
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1308
|
+
logger20.warn(
|
|
1309
|
+
"search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry",
|
|
1310
|
+
{
|
|
1311
|
+
query,
|
|
1312
|
+
limit,
|
|
1313
|
+
totalSize: response.data.totalSize
|
|
1314
|
+
}
|
|
1315
|
+
);
|
|
1275
1316
|
} else {
|
|
1276
1317
|
logger20.info("search-confluence result", {
|
|
1277
1318
|
query,
|
|
@@ -1288,28 +1329,33 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1288
1329
|
results
|
|
1289
1330
|
});
|
|
1290
1331
|
} catch (error) {
|
|
1332
|
+
const description = request2.describeError(error);
|
|
1291
1333
|
logger20.error("search-confluence error", {
|
|
1292
1334
|
query,
|
|
1293
|
-
error:
|
|
1294
|
-
status:
|
|
1335
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1336
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1295
1337
|
});
|
|
1296
1338
|
return JSON.stringify({
|
|
1297
1339
|
success: false,
|
|
1298
|
-
error:
|
|
1340
|
+
error: description.message
|
|
1299
1341
|
});
|
|
1300
1342
|
}
|
|
1301
1343
|
}).build();
|
|
1302
1344
|
}
|
|
1303
|
-
function createGetConfluencePageTool(
|
|
1304
|
-
return toolBuilder().name("get-confluence-page").description(
|
|
1305
|
-
|
|
1306
|
-
|
|
1345
|
+
function createGetConfluencePageTool(request2, logger20) {
|
|
1346
|
+
return toolBuilder().name("get-confluence-page").description(
|
|
1347
|
+
"Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata."
|
|
1348
|
+
).category(ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes(
|
|
1349
|
+
"Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results."
|
|
1350
|
+
).requires(["search-confluence"]).schema(
|
|
1351
|
+
z.object({
|
|
1352
|
+
page_id: z.string().describe("The Confluence page ID (from search results)")
|
|
1353
|
+
})
|
|
1354
|
+
).implement(async ({ page_id }) => {
|
|
1307
1355
|
logger20.info("get-confluence-page called", { page_id });
|
|
1308
1356
|
try {
|
|
1309
|
-
const
|
|
1310
|
-
const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
|
|
1357
|
+
const response = await request2.get(`/wiki/rest/api/content/${page_id}`, {
|
|
1311
1358
|
headers: {
|
|
1312
|
-
Authorization: getAuthHeader2(),
|
|
1313
1359
|
Accept: "application/json"
|
|
1314
1360
|
},
|
|
1315
1361
|
params: {
|
|
@@ -1332,35 +1378,40 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1332
1378
|
space: page.space?.name || "Unknown",
|
|
1333
1379
|
spaceKey: page.space?.key || "",
|
|
1334
1380
|
content: page.body?.storage?.value || "",
|
|
1335
|
-
url: `${
|
|
1381
|
+
url: `${response.siteUrl}/wiki${page._links.webui}`,
|
|
1336
1382
|
created: page.history?.createdDate || "",
|
|
1337
1383
|
lastModified: page.version?.when || "",
|
|
1338
1384
|
version: page.version?.number || 1
|
|
1339
1385
|
}
|
|
1340
1386
|
});
|
|
1341
1387
|
} catch (error) {
|
|
1388
|
+
const description = request2.describeError(error);
|
|
1342
1389
|
logger20.error("get-confluence-page error", {
|
|
1343
1390
|
page_id,
|
|
1344
|
-
error:
|
|
1345
|
-
status:
|
|
1391
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1392
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1346
1393
|
});
|
|
1347
1394
|
return JSON.stringify({
|
|
1348
1395
|
success: false,
|
|
1349
|
-
error:
|
|
1396
|
+
error: description.message
|
|
1350
1397
|
});
|
|
1351
1398
|
}
|
|
1352
1399
|
}).build();
|
|
1353
1400
|
}
|
|
1354
|
-
function createListConfluenceSpacesTool(
|
|
1355
|
-
return toolBuilder().name("list-confluence-spaces").description(
|
|
1356
|
-
|
|
1357
|
-
|
|
1401
|
+
function createListConfluenceSpacesTool(request2, logger20) {
|
|
1402
|
+
return toolBuilder().name("list-confluence-spaces").description(
|
|
1403
|
+
"List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information."
|
|
1404
|
+
).category(ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes(
|
|
1405
|
+
"Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance')."
|
|
1406
|
+
).follows(["search-confluence"]).schema(
|
|
1407
|
+
z.object({
|
|
1408
|
+
limit: z.number().optional().describe("Maximum number of spaces to return (default: 25)")
|
|
1409
|
+
})
|
|
1410
|
+
).implement(async ({ limit = 25 }) => {
|
|
1358
1411
|
logger20.info("list-confluence-spaces called", { limit });
|
|
1359
1412
|
try {
|
|
1360
|
-
const
|
|
1361
|
-
const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
|
|
1413
|
+
const response = await request2.get("/wiki/rest/api/space", {
|
|
1362
1414
|
headers: {
|
|
1363
|
-
Authorization: getAuthHeader2(),
|
|
1364
1415
|
Accept: "application/json"
|
|
1365
1416
|
},
|
|
1366
1417
|
params: {
|
|
@@ -1372,7 +1423,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1372
1423
|
name: space.name,
|
|
1373
1424
|
type: space.type,
|
|
1374
1425
|
description: space.description?.plain?.value || "",
|
|
1375
|
-
url: `${
|
|
1426
|
+
url: `${response.siteUrl}/wiki${space._links.webui}`
|
|
1376
1427
|
}));
|
|
1377
1428
|
logger20.info("list-confluence-spaces result", {
|
|
1378
1429
|
spaceCount: spaces.length,
|
|
@@ -1385,28 +1436,33 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1385
1436
|
spaces
|
|
1386
1437
|
});
|
|
1387
1438
|
} catch (error) {
|
|
1439
|
+
const description = request2.describeError(error);
|
|
1388
1440
|
logger20.error("list-confluence-spaces error", {
|
|
1389
|
-
error:
|
|
1390
|
-
status:
|
|
1441
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1442
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1391
1443
|
});
|
|
1392
1444
|
return JSON.stringify({
|
|
1393
1445
|
success: false,
|
|
1394
|
-
error:
|
|
1446
|
+
error: description.message
|
|
1395
1447
|
});
|
|
1396
1448
|
}
|
|
1397
1449
|
}).build();
|
|
1398
1450
|
}
|
|
1399
|
-
function createGetSpacePagesTool(
|
|
1400
|
-
return toolBuilder().name("get-space-pages").description(
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1451
|
+
function createGetSpacePagesTool(request2, logger20) {
|
|
1452
|
+
return toolBuilder().name("get-space-pages").description(
|
|
1453
|
+
"Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area."
|
|
1454
|
+
).category(ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes(
|
|
1455
|
+
"Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first."
|
|
1456
|
+
).requires(["list-confluence-spaces"]).schema(
|
|
1457
|
+
z.object({
|
|
1458
|
+
space_key: z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
|
|
1459
|
+
limit: z.number().optional().describe("Maximum number of pages to return (default: 25)")
|
|
1460
|
+
})
|
|
1461
|
+
).implement(async ({ space_key, limit = 25 }) => {
|
|
1404
1462
|
logger20.info("get-space-pages called", { space_key, limit });
|
|
1405
1463
|
try {
|
|
1406
|
-
const
|
|
1407
|
-
const response = await axios11.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
|
|
1464
|
+
const response = await request2.get("/wiki/rest/api/content", {
|
|
1408
1465
|
headers: {
|
|
1409
|
-
Authorization: getAuthHeader2(),
|
|
1410
1466
|
Accept: "application/json"
|
|
1411
1467
|
},
|
|
1412
1468
|
params: {
|
|
@@ -1419,14 +1475,17 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1419
1475
|
const pages = response.data.results.map((page) => ({
|
|
1420
1476
|
id: page.id,
|
|
1421
1477
|
title: page.title,
|
|
1422
|
-
url: `${
|
|
1478
|
+
url: `${response.siteUrl}/wiki${page._links.webui}`,
|
|
1423
1479
|
lastModified: page.version?.when || ""
|
|
1424
1480
|
}));
|
|
1425
1481
|
if (pages.length === 0) {
|
|
1426
|
-
logger20.warn(
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1482
|
+
logger20.warn(
|
|
1483
|
+
"get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry",
|
|
1484
|
+
{
|
|
1485
|
+
space_key,
|
|
1486
|
+
limit
|
|
1487
|
+
}
|
|
1488
|
+
);
|
|
1430
1489
|
} else {
|
|
1431
1490
|
logger20.info("get-space-pages result", {
|
|
1432
1491
|
space_key,
|
|
@@ -1442,28 +1501,38 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1442
1501
|
pages
|
|
1443
1502
|
});
|
|
1444
1503
|
} catch (error) {
|
|
1504
|
+
const description = request2.describeError(error);
|
|
1445
1505
|
logger20.error("get-space-pages error", {
|
|
1446
1506
|
space_key,
|
|
1447
|
-
error:
|
|
1448
|
-
status:
|
|
1507
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1508
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1449
1509
|
});
|
|
1450
1510
|
return JSON.stringify({
|
|
1451
1511
|
success: false,
|
|
1452
|
-
error:
|
|
1512
|
+
error: description.message
|
|
1453
1513
|
});
|
|
1454
1514
|
}
|
|
1455
1515
|
}).build();
|
|
1456
1516
|
}
|
|
1457
|
-
function createCreateConfluencePageTool(
|
|
1458
|
-
return toolBuilder().name("create-confluence-page").description(
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1517
|
+
function createCreateConfluencePageTool(request2, logger20) {
|
|
1518
|
+
return toolBuilder().name("create-confluence-page").description(
|
|
1519
|
+
"Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format)."
|
|
1520
|
+
).category(ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes(
|
|
1521
|
+
"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."
|
|
1522
|
+
).requires(["list-confluence-spaces"]).schema(
|
|
1523
|
+
z.object({
|
|
1524
|
+
space_key: z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
|
|
1525
|
+
title: z.string().describe("The title of the new page"),
|
|
1526
|
+
content: z.string().describe("The page content in HTML format (Confluence storage format)"),
|
|
1527
|
+
parent_page_id: z.string().optional().describe("Optional parent page ID to create this as a child page")
|
|
1528
|
+
})
|
|
1529
|
+
).implement(async ({ space_key, title, content, parent_page_id }) => {
|
|
1530
|
+
logger20.info("create-confluence-page called", {
|
|
1531
|
+
space_key,
|
|
1532
|
+
title,
|
|
1533
|
+
hasParent: !!parent_page_id
|
|
1534
|
+
});
|
|
1465
1535
|
try {
|
|
1466
|
-
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1467
1536
|
const pageData = {
|
|
1468
1537
|
type: "page",
|
|
1469
1538
|
title,
|
|
@@ -1478,16 +1547,11 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1478
1547
|
if (parent_page_id) {
|
|
1479
1548
|
pageData.ancestors = [{ id: parent_page_id }];
|
|
1480
1549
|
}
|
|
1481
|
-
const response = await
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
{
|
|
1485
|
-
headers: {
|
|
1486
|
-
Authorization: getAuthHeader2(),
|
|
1487
|
-
"Content-Type": "application/json"
|
|
1488
|
-
}
|
|
1550
|
+
const response = await request2.post("/wiki/rest/api/content", pageData, {
|
|
1551
|
+
headers: {
|
|
1552
|
+
"Content-Type": "application/json"
|
|
1489
1553
|
}
|
|
1490
|
-
);
|
|
1554
|
+
});
|
|
1491
1555
|
logger20.info("create-confluence-page result", {
|
|
1492
1556
|
page_id: response.data.id,
|
|
1493
1557
|
title: response.data.title,
|
|
@@ -1499,45 +1563,45 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1499
1563
|
id: response.data.id,
|
|
1500
1564
|
title: response.data.title,
|
|
1501
1565
|
space: space_key,
|
|
1502
|
-
url: `${
|
|
1566
|
+
url: `${response.siteUrl}/wiki${response.data._links.webui}`,
|
|
1503
1567
|
version: response.data.version?.number || 1
|
|
1504
1568
|
}
|
|
1505
1569
|
});
|
|
1506
1570
|
} catch (error) {
|
|
1571
|
+
const description = request2.describeError(error);
|
|
1507
1572
|
logger20.error("create-confluence-page error", {
|
|
1508
1573
|
space_key,
|
|
1509
1574
|
title,
|
|
1510
|
-
error:
|
|
1511
|
-
status:
|
|
1575
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1576
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1512
1577
|
});
|
|
1513
1578
|
return JSON.stringify({
|
|
1514
1579
|
success: false,
|
|
1515
|
-
error:
|
|
1580
|
+
error: description.message
|
|
1516
1581
|
});
|
|
1517
1582
|
}
|
|
1518
1583
|
}).build();
|
|
1519
1584
|
}
|
|
1520
|
-
function createUpdateConfluencePageTool(
|
|
1521
|
-
return toolBuilder().name("update-confluence-page").description(
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1585
|
+
function createUpdateConfluencePageTool(request2, logger20) {
|
|
1586
|
+
return toolBuilder().name("update-confluence-page").description(
|
|
1587
|
+
"Update an existing Confluence page's content. Requires page ID, new title, and new content."
|
|
1588
|
+
).category(ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes(
|
|
1589
|
+
"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."
|
|
1590
|
+
).requires(["get-confluence-page"]).schema(
|
|
1591
|
+
z.object({
|
|
1592
|
+
page_id: z.string().describe("The ID of the page to update"),
|
|
1593
|
+
title: z.string().describe("The new title for the page"),
|
|
1594
|
+
content: z.string().describe("The new content in HTML format (Confluence storage format)")
|
|
1595
|
+
})
|
|
1596
|
+
).implement(async ({ page_id, title, content }) => {
|
|
1526
1597
|
logger20.info("update-confluence-page called", { page_id, title });
|
|
1527
1598
|
try {
|
|
1528
|
-
const
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
{
|
|
1532
|
-
headers: {
|
|
1533
|
-
Authorization: getAuthHeader2()
|
|
1534
|
-
},
|
|
1535
|
-
params: { expand: "version" }
|
|
1536
|
-
}
|
|
1537
|
-
);
|
|
1599
|
+
const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
|
|
1600
|
+
params: { expand: "version" }
|
|
1601
|
+
});
|
|
1538
1602
|
const currentVersion = getResponse.data.version.number;
|
|
1539
|
-
const updateResponse = await
|
|
1540
|
-
|
|
1603
|
+
const updateResponse = await request2.put(
|
|
1604
|
+
`/wiki/rest/api/content/${page_id}`,
|
|
1541
1605
|
{
|
|
1542
1606
|
type: "page",
|
|
1543
1607
|
title,
|
|
@@ -1551,7 +1615,6 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1551
1615
|
},
|
|
1552
1616
|
{
|
|
1553
1617
|
headers: {
|
|
1554
|
-
Authorization: getAuthHeader2(),
|
|
1555
1618
|
"Content-Type": "application/json"
|
|
1556
1619
|
}
|
|
1557
1620
|
}
|
|
@@ -1567,49 +1630,49 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1567
1630
|
page: {
|
|
1568
1631
|
id: updateResponse.data.id,
|
|
1569
1632
|
title: updateResponse.data.title,
|
|
1570
|
-
url: `${
|
|
1633
|
+
url: `${updateResponse.siteUrl}/wiki${updateResponse.data._links.webui}`,
|
|
1571
1634
|
version: updateResponse.data.version.number,
|
|
1572
1635
|
previousVersion: currentVersion
|
|
1573
1636
|
}
|
|
1574
1637
|
});
|
|
1575
1638
|
} catch (error) {
|
|
1639
|
+
const description = request2.describeError(error);
|
|
1576
1640
|
logger20.error("update-confluence-page error", {
|
|
1577
1641
|
page_id,
|
|
1578
1642
|
title,
|
|
1579
|
-
error:
|
|
1580
|
-
status:
|
|
1643
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1644
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1581
1645
|
});
|
|
1582
1646
|
return JSON.stringify({
|
|
1583
1647
|
success: false,
|
|
1584
|
-
error:
|
|
1648
|
+
error: description.message
|
|
1585
1649
|
});
|
|
1586
1650
|
}
|
|
1587
1651
|
}).build();
|
|
1588
1652
|
}
|
|
1589
|
-
function createArchiveConfluencePageTool(
|
|
1590
|
-
return toolBuilder().name("archive-confluence-page").description(
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1653
|
+
function createArchiveConfluencePageTool(request2, logger20) {
|
|
1654
|
+
return toolBuilder().name("archive-confluence-page").description(
|
|
1655
|
+
"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."
|
|
1656
|
+
).category(ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes(
|
|
1657
|
+
"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."
|
|
1658
|
+
).conflicts(["create-confluence-page"]).schema(
|
|
1659
|
+
z.object({
|
|
1660
|
+
page_id: z.string().describe("The ID of the page to archive"),
|
|
1661
|
+
reason: z.string().optional().describe("Optional reason for archiving (for audit trail)")
|
|
1662
|
+
})
|
|
1663
|
+
).implement(async ({ page_id, reason }) => {
|
|
1594
1664
|
logger20.info("archive-confluence-page called", {
|
|
1595
1665
|
page_id,
|
|
1596
1666
|
...reason ? { reason } : {}
|
|
1597
1667
|
});
|
|
1598
1668
|
try {
|
|
1599
|
-
const
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
{
|
|
1603
|
-
headers: {
|
|
1604
|
-
Authorization: getAuthHeader2()
|
|
1605
|
-
},
|
|
1606
|
-
params: { expand: "version,body.storage,space" }
|
|
1607
|
-
}
|
|
1608
|
-
);
|
|
1669
|
+
const getResponse = await request2.get(`/wiki/rest/api/content/${page_id}`, {
|
|
1670
|
+
params: { expand: "version,body.storage,space" }
|
|
1671
|
+
});
|
|
1609
1672
|
const currentVersion = getResponse.data.version.number;
|
|
1610
1673
|
const pageData = getResponse.data;
|
|
1611
|
-
await
|
|
1612
|
-
|
|
1674
|
+
await request2.put(
|
|
1675
|
+
`/wiki/rest/api/content/${page_id}`,
|
|
1613
1676
|
{
|
|
1614
1677
|
version: { number: currentVersion + 1 },
|
|
1615
1678
|
title: pageData.title,
|
|
@@ -1620,7 +1683,6 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1620
1683
|
},
|
|
1621
1684
|
{
|
|
1622
1685
|
headers: {
|
|
1623
|
-
Authorization: getAuthHeader2(),
|
|
1624
1686
|
"Content-Type": "application/json"
|
|
1625
1687
|
}
|
|
1626
1688
|
}
|
|
@@ -1643,14 +1705,15 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1643
1705
|
}
|
|
1644
1706
|
});
|
|
1645
1707
|
} catch (error) {
|
|
1708
|
+
const description = request2.describeError(error);
|
|
1646
1709
|
logger20.error("archive-confluence-page error", {
|
|
1647
1710
|
page_id,
|
|
1648
|
-
error:
|
|
1649
|
-
status:
|
|
1711
|
+
...description.message !== void 0 ? { error: description.message } : {},
|
|
1712
|
+
...description.status !== void 0 ? { status: description.status } : {}
|
|
1650
1713
|
});
|
|
1651
1714
|
return JSON.stringify({
|
|
1652
1715
|
success: false,
|
|
1653
|
-
error:
|
|
1716
|
+
error: description.message
|
|
1654
1717
|
});
|
|
1655
1718
|
}
|
|
1656
1719
|
}).build();
|
|
@@ -1659,13 +1722,14 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger20) {
|
|
|
1659
1722
|
// src/web/confluence/index.ts
|
|
1660
1723
|
var logLevel2 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
|
|
1661
1724
|
var logger2 = createLogger("[tools:confluence]", { level: logLevel2 });
|
|
1662
|
-
var
|
|
1663
|
-
var
|
|
1664
|
-
var
|
|
1665
|
-
var
|
|
1666
|
-
var
|
|
1667
|
-
var
|
|
1668
|
-
var
|
|
1725
|
+
var request = createConfluenceRequest(getConfig);
|
|
1726
|
+
var searchConfluence = createSearchConfluenceTool(request, logger2);
|
|
1727
|
+
var getConfluencePage = createGetConfluencePageTool(request, logger2);
|
|
1728
|
+
var listConfluenceSpaces = createListConfluenceSpacesTool(request, logger2);
|
|
1729
|
+
var getSpacePages = createGetSpacePagesTool(request, logger2);
|
|
1730
|
+
var createConfluencePage = createCreateConfluencePageTool(request, logger2);
|
|
1731
|
+
var updateConfluencePage = createUpdateConfluencePageTool(request, logger2);
|
|
1732
|
+
var archiveConfluencePage = createArchiveConfluencePageTool(request, logger2);
|
|
1669
1733
|
var confluenceTools = [
|
|
1670
1734
|
// Read tools
|
|
1671
1735
|
searchConfluence,
|
|
@@ -1678,22 +1742,17 @@ var confluenceTools = [
|
|
|
1678
1742
|
archiveConfluencePage
|
|
1679
1743
|
];
|
|
1680
1744
|
function createConfluenceTools(config = {}) {
|
|
1681
|
-
const {
|
|
1682
|
-
apiKey,
|
|
1683
|
-
email,
|
|
1684
|
-
siteUrl,
|
|
1685
|
-
logLevel: customLogLevel
|
|
1686
|
-
} = config;
|
|
1745
|
+
const { apiKey, email, siteUrl, logLevel: customLogLevel } = config;
|
|
1687
1746
|
const getConfiguredAuth = createGetConfiguredAuth(apiKey, email, siteUrl);
|
|
1688
|
-
const
|
|
1747
|
+
const request2 = createConfluenceRequest(getConfiguredAuth);
|
|
1689
1748
|
const toolLogger = customLogLevel ? createLogger("tools:confluence", { level: customLogLevel }) : logger2;
|
|
1690
|
-
const searchConfluence2 = createSearchConfluenceTool(
|
|
1691
|
-
const getConfluencePage2 = createGetConfluencePageTool(
|
|
1692
|
-
const listConfluenceSpaces2 = createListConfluenceSpacesTool(
|
|
1693
|
-
const getSpacePages2 = createGetSpacePagesTool(
|
|
1694
|
-
const createConfluencePage2 = createCreateConfluencePageTool(
|
|
1695
|
-
const updateConfluencePage2 = createUpdateConfluencePageTool(
|
|
1696
|
-
const archiveConfluencePage2 = createArchiveConfluencePageTool(
|
|
1749
|
+
const searchConfluence2 = createSearchConfluenceTool(request2, toolLogger);
|
|
1750
|
+
const getConfluencePage2 = createGetConfluencePageTool(request2, toolLogger);
|
|
1751
|
+
const listConfluenceSpaces2 = createListConfluenceSpacesTool(request2, toolLogger);
|
|
1752
|
+
const getSpacePages2 = createGetSpacePagesTool(request2, toolLogger);
|
|
1753
|
+
const createConfluencePage2 = createCreateConfluencePageTool(request2, toolLogger);
|
|
1754
|
+
const updateConfluencePage2 = createUpdateConfluencePageTool(request2, toolLogger);
|
|
1755
|
+
const archiveConfluencePage2 = createArchiveConfluencePageTool(request2, toolLogger);
|
|
1697
1756
|
return {
|
|
1698
1757
|
searchConfluence: searchConfluence2,
|
|
1699
1758
|
getConfluencePage: getConfluencePage2,
|
|
@@ -1884,14 +1943,14 @@ function createJsonStringifyTool(defaultIndent = 2, defaultPretty = false) {
|
|
|
1884
1943
|
};
|
|
1885
1944
|
}).build();
|
|
1886
1945
|
}
|
|
1887
|
-
function
|
|
1946
|
+
function isRecord2(value) {
|
|
1888
1947
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1889
1948
|
}
|
|
1890
1949
|
function getPathValue(current, part) {
|
|
1891
1950
|
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
|
|
1892
1951
|
if (arrayMatch) {
|
|
1893
1952
|
const [, key, index] = arrayMatch;
|
|
1894
|
-
if (!
|
|
1953
|
+
if (!isRecord2(current)) {
|
|
1895
1954
|
return void 0;
|
|
1896
1955
|
}
|
|
1897
1956
|
const candidate = current[key];
|
|
@@ -1900,7 +1959,7 @@ function getPathValue(current, part) {
|
|
|
1900
1959
|
}
|
|
1901
1960
|
return candidate[parseInt(index, 10)];
|
|
1902
1961
|
}
|
|
1903
|
-
if (!
|
|
1962
|
+
if (!isRecord2(current)) {
|
|
1904
1963
|
return void 0;
|
|
1905
1964
|
}
|
|
1906
1965
|
return current[part];
|
|
@@ -2556,7 +2615,7 @@ async function initializeFromEnv() {
|
|
|
2556
2615
|
// src/data/neo4j/embeddings/utils.ts
|
|
2557
2616
|
function withProviderErrorMetadata(error, message) {
|
|
2558
2617
|
const wrappedError = new Error(message);
|
|
2559
|
-
if (!
|
|
2618
|
+
if (!isRecord3(error)) return wrappedError;
|
|
2560
2619
|
if (typeof error.code === "string") wrappedError.code = error.code;
|
|
2561
2620
|
if (error.response !== void 0) wrappedError.response = error.response;
|
|
2562
2621
|
return wrappedError;
|
|
@@ -2569,12 +2628,12 @@ var DEFAULT_RETRY_CONFIG2 = {
|
|
|
2569
2628
|
// 10 seconds
|
|
2570
2629
|
backoffMultiplier: 2
|
|
2571
2630
|
};
|
|
2572
|
-
function
|
|
2631
|
+
function isRecord3(value) {
|
|
2573
2632
|
return typeof value === "object" && value !== null;
|
|
2574
2633
|
}
|
|
2575
2634
|
function isRetryableError2(error) {
|
|
2576
|
-
if (!
|
|
2577
|
-
const response =
|
|
2635
|
+
if (!isRecord3(error)) return false;
|
|
2636
|
+
const response = isRecord3(error.response) ? error.response : void 0;
|
|
2578
2637
|
const status = typeof response?.status === "number" ? response.status : void 0;
|
|
2579
2638
|
const code = typeof error.code === "string" ? error.code : void 0;
|
|
2580
2639
|
const message = typeof error.message === "string" ? error.message : void 0;
|
|
@@ -2700,7 +2759,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
2700
2759
|
const modelToUse = model || this.defaultModel;
|
|
2701
2760
|
return retryWithBackoff2(async () => {
|
|
2702
2761
|
try {
|
|
2703
|
-
const response = await
|
|
2762
|
+
const response = await axios5.post(
|
|
2704
2763
|
`${this.baseURL}/embeddings`,
|
|
2705
2764
|
{
|
|
2706
2765
|
input: text,
|
|
@@ -2730,7 +2789,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
2730
2789
|
};
|
|
2731
2790
|
} catch (error) {
|
|
2732
2791
|
let message;
|
|
2733
|
-
const response =
|
|
2792
|
+
const response = axios5.isAxiosError(error) ? error.response : void 0;
|
|
2734
2793
|
if (response?.status === 401) {
|
|
2735
2794
|
message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
|
|
2736
2795
|
} else if (response?.status === 429) {
|
|
@@ -2757,7 +2816,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
2757
2816
|
const modelToUse = model || this.defaultModel;
|
|
2758
2817
|
return retryWithBackoff2(async () => {
|
|
2759
2818
|
try {
|
|
2760
|
-
const response = await
|
|
2819
|
+
const response = await axios5.post(
|
|
2761
2820
|
`${this.baseURL}/embeddings`,
|
|
2762
2821
|
{
|
|
2763
2822
|
input: texts,
|
|
@@ -2788,7 +2847,7 @@ var OpenAIEmbeddingProvider = class {
|
|
|
2788
2847
|
};
|
|
2789
2848
|
} catch (error) {
|
|
2790
2849
|
let message;
|
|
2791
|
-
const response =
|
|
2850
|
+
const response = axios5.isAxiosError(error) ? error.response : void 0;
|
|
2792
2851
|
if (response?.status === 401) {
|
|
2793
2852
|
message = "Invalid OpenAI API key. Get your key at https://platform.openai.com/api-keys";
|
|
2794
2853
|
} else if (response?.status === 429) {
|
|
@@ -2830,7 +2889,7 @@ var CohereEmbeddingProvider = class {
|
|
|
2830
2889
|
const modelToUse = model || this.defaultModel;
|
|
2831
2890
|
return retryWithBackoff2(async () => {
|
|
2832
2891
|
try {
|
|
2833
|
-
const response = await
|
|
2892
|
+
const response = await axios5.post(
|
|
2834
2893
|
`${this.baseUrl}/embed`,
|
|
2835
2894
|
{
|
|
2836
2895
|
texts,
|
|
@@ -2858,7 +2917,7 @@ var CohereEmbeddingProvider = class {
|
|
|
2858
2917
|
} : void 0
|
|
2859
2918
|
};
|
|
2860
2919
|
} catch (error) {
|
|
2861
|
-
if (
|
|
2920
|
+
if (axios5.isAxiosError(error)) {
|
|
2862
2921
|
const status = error.response?.status;
|
|
2863
2922
|
const providerMessage = error.response?.data?.message || error.message;
|
|
2864
2923
|
let message;
|
|
@@ -2893,80 +2952,54 @@ var HuggingFaceEmbeddingProvider = class {
|
|
|
2893
2952
|
return !!this.apiKey;
|
|
2894
2953
|
}
|
|
2895
2954
|
async generateEmbedding(text, model) {
|
|
2896
|
-
const modelToUse =
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
},
|
|
2907
|
-
{
|
|
2908
|
-
headers: {
|
|
2909
|
-
"Authorization": `Bearer ${this.apiKey}`,
|
|
2910
|
-
"Content-Type": "application/json"
|
|
2911
|
-
}
|
|
2912
|
-
}
|
|
2913
|
-
);
|
|
2914
|
-
const embedding = Array.isArray(response.data) ? response.data : response.data[0];
|
|
2915
|
-
return {
|
|
2916
|
-
embedding,
|
|
2917
|
-
model: modelToUse,
|
|
2918
|
-
dimensions: embedding.length
|
|
2919
|
-
};
|
|
2920
|
-
} catch (error) {
|
|
2921
|
-
if (axios11.isAxiosError(error)) {
|
|
2922
|
-
const status = error.response?.status;
|
|
2923
|
-
const message = error.response?.data?.error || error.message;
|
|
2924
|
-
let messageText;
|
|
2925
|
-
if (status === 401) {
|
|
2926
|
-
messageText = `HuggingFace API authentication failed. Please check your HUGGINGFACE_API_KEY. ${message}`;
|
|
2927
|
-
} else if (status === 429) {
|
|
2928
|
-
messageText = `HuggingFace API rate limit exceeded. ${message}`;
|
|
2929
|
-
} else if (status === 400) {
|
|
2930
|
-
messageText = `HuggingFace API request invalid: ${message}`;
|
|
2931
|
-
} else if (status === 503) {
|
|
2932
|
-
messageText = `HuggingFace model is loading. Please retry in a moment. ${message}`;
|
|
2933
|
-
} else {
|
|
2934
|
-
messageText = `HuggingFace API error (${status}): ${message}`;
|
|
2935
|
-
}
|
|
2936
|
-
throw withProviderErrorMetadata(error, messageText);
|
|
2937
|
-
}
|
|
2938
|
-
throw error;
|
|
2939
|
-
}
|
|
2940
|
-
});
|
|
2955
|
+
const { data, model: modelToUse } = await this.requestEmbeddings(
|
|
2956
|
+
text,
|
|
2957
|
+
model
|
|
2958
|
+
);
|
|
2959
|
+
const embedding = Array.isArray(data) ? data : data[0];
|
|
2960
|
+
return {
|
|
2961
|
+
embedding,
|
|
2962
|
+
model: modelToUse,
|
|
2963
|
+
dimensions: embedding.length
|
|
2964
|
+
};
|
|
2941
2965
|
}
|
|
2942
2966
|
async generateBatchEmbeddings(texts, model) {
|
|
2967
|
+
const { data: embeddings, model: modelToUse } = await this.requestEmbeddings(
|
|
2968
|
+
texts,
|
|
2969
|
+
model
|
|
2970
|
+
);
|
|
2971
|
+
const dimensions = embeddings[0]?.length || 0;
|
|
2972
|
+
return {
|
|
2973
|
+
embeddings,
|
|
2974
|
+
model: modelToUse,
|
|
2975
|
+
dimensions
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
async requestEmbeddings(inputs, model) {
|
|
2943
2979
|
const modelToUse = model || this.defaultModel;
|
|
2944
2980
|
return retryWithBackoff2(async () => {
|
|
2945
2981
|
try {
|
|
2946
|
-
const response = await
|
|
2982
|
+
const response = await axios5.post(
|
|
2947
2983
|
`${this.baseUrl}/${modelToUse}`,
|
|
2948
2984
|
{
|
|
2949
|
-
inputs
|
|
2985
|
+
inputs,
|
|
2950
2986
|
options: {
|
|
2951
2987
|
wait_for_model: true
|
|
2952
2988
|
}
|
|
2953
2989
|
},
|
|
2954
2990
|
{
|
|
2955
2991
|
headers: {
|
|
2956
|
-
|
|
2992
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
2957
2993
|
"Content-Type": "application/json"
|
|
2958
2994
|
}
|
|
2959
2995
|
}
|
|
2960
2996
|
);
|
|
2961
|
-
const embeddings = response.data;
|
|
2962
|
-
const dimensions = embeddings[0]?.length || 0;
|
|
2963
2997
|
return {
|
|
2964
|
-
|
|
2965
|
-
model: modelToUse
|
|
2966
|
-
dimensions
|
|
2998
|
+
data: response.data,
|
|
2999
|
+
model: modelToUse
|
|
2967
3000
|
};
|
|
2968
3001
|
} catch (error) {
|
|
2969
|
-
if (
|
|
3002
|
+
if (axios5.isAxiosError(error)) {
|
|
2970
3003
|
const status = error.response?.status;
|
|
2971
3004
|
const message = error.response?.data?.error || error.message;
|
|
2972
3005
|
let messageText;
|
|
@@ -3015,7 +3048,7 @@ var VoyageEmbeddingProvider = class {
|
|
|
3015
3048
|
const modelToUse = model || this.defaultModel;
|
|
3016
3049
|
return retryWithBackoff2(async () => {
|
|
3017
3050
|
try {
|
|
3018
|
-
const response = await
|
|
3051
|
+
const response = await axios5.post(
|
|
3019
3052
|
`${this.baseUrl}/embeddings`,
|
|
3020
3053
|
{
|
|
3021
3054
|
input: texts,
|
|
@@ -3042,7 +3075,7 @@ var VoyageEmbeddingProvider = class {
|
|
|
3042
3075
|
} : void 0
|
|
3043
3076
|
};
|
|
3044
3077
|
} catch (error) {
|
|
3045
|
-
if (
|
|
3078
|
+
if (axios5.isAxiosError(error)) {
|
|
3046
3079
|
const status = error.response?.status;
|
|
3047
3080
|
const message = error.response?.data?.message || error.message;
|
|
3048
3081
|
let messageText;
|
|
@@ -3079,7 +3112,7 @@ var OllamaEmbeddingProvider = class {
|
|
|
3079
3112
|
const modelToUse = model || this.defaultModel;
|
|
3080
3113
|
return retryWithBackoff2(async () => {
|
|
3081
3114
|
try {
|
|
3082
|
-
const response = await
|
|
3115
|
+
const response = await axios5.post(
|
|
3083
3116
|
`${this.baseUrl}/api/embeddings`,
|
|
3084
3117
|
{
|
|
3085
3118
|
model: modelToUse,
|
|
@@ -3098,7 +3131,7 @@ var OllamaEmbeddingProvider = class {
|
|
|
3098
3131
|
dimensions: embedding.length
|
|
3099
3132
|
};
|
|
3100
3133
|
} catch (error) {
|
|
3101
|
-
if (
|
|
3134
|
+
if (axios5.isAxiosError(error)) {
|
|
3102
3135
|
const status = error.response?.status;
|
|
3103
3136
|
const message = error.response?.data?.error || error.message;
|
|
3104
3137
|
let messageText;
|
|
@@ -3491,6 +3524,16 @@ function formatResults(records) {
|
|
|
3491
3524
|
});
|
|
3492
3525
|
}
|
|
3493
3526
|
|
|
3527
|
+
// src/data/neo4j/tools/session-owner.ts
|
|
3528
|
+
async function withNeo4jSession(database, operation) {
|
|
3529
|
+
const session = neo4jPool.getSession(database);
|
|
3530
|
+
try {
|
|
3531
|
+
return await operation(session);
|
|
3532
|
+
} finally {
|
|
3533
|
+
await session.close();
|
|
3534
|
+
}
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3494
3537
|
// src/data/neo4j/tools/neo4j-query.ts
|
|
3495
3538
|
var logger4 = createLogger("agentforge:tools:neo4j:query");
|
|
3496
3539
|
function createNeo4jQueryTool() {
|
|
@@ -3511,8 +3554,7 @@ function createNeo4jQueryTool() {
|
|
|
3511
3554
|
...input.database ? { database: input.database } : {}
|
|
3512
3555
|
});
|
|
3513
3556
|
try {
|
|
3514
|
-
|
|
3515
|
-
try {
|
|
3557
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3516
3558
|
const result = await session.run(input.cypher, input.parameters || {});
|
|
3517
3559
|
const formattedResults = formatResults(result.records);
|
|
3518
3560
|
const duration = Date.now() - startTime;
|
|
@@ -3541,9 +3583,7 @@ function createNeo4jQueryTool() {
|
|
|
3541
3583
|
}
|
|
3542
3584
|
}
|
|
3543
3585
|
};
|
|
3544
|
-
}
|
|
3545
|
-
await session.close();
|
|
3546
|
-
}
|
|
3586
|
+
});
|
|
3547
3587
|
} catch (error) {
|
|
3548
3588
|
const duration = Date.now() - startTime;
|
|
3549
3589
|
const errorMessage = error instanceof Error ? error.message : "Failed to execute query";
|
|
@@ -3571,8 +3611,7 @@ function createNeo4jGetSchemaTool() {
|
|
|
3571
3611
|
};
|
|
3572
3612
|
}
|
|
3573
3613
|
try {
|
|
3574
|
-
|
|
3575
|
-
try {
|
|
3614
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3576
3615
|
const labelsResult = await session.run("CALL db.labels()");
|
|
3577
3616
|
const nodeLabels = labelsResult.records.map((r) => r.get("label"));
|
|
3578
3617
|
const relTypesResult = await session.run("CALL db.relationshipTypes()");
|
|
@@ -3612,9 +3651,7 @@ function createNeo4jGetSchemaTool() {
|
|
|
3612
3651
|
totalIndexes: indexes.length
|
|
3613
3652
|
}
|
|
3614
3653
|
};
|
|
3615
|
-
}
|
|
3616
|
-
await session.close();
|
|
3617
|
-
}
|
|
3654
|
+
});
|
|
3618
3655
|
} catch (error) {
|
|
3619
3656
|
return {
|
|
3620
3657
|
success: false,
|
|
@@ -3693,8 +3730,7 @@ function createNeo4jFindNodesTool() {
|
|
|
3693
3730
|
}
|
|
3694
3731
|
try {
|
|
3695
3732
|
const safeLabel = validateLabel(input.label);
|
|
3696
|
-
|
|
3697
|
-
try {
|
|
3733
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3698
3734
|
let cypher = `MATCH (n:${safeLabel})`;
|
|
3699
3735
|
let parameters = {};
|
|
3700
3736
|
if (input.properties && Object.keys(input.properties).length > 0) {
|
|
@@ -3716,9 +3752,7 @@ function createNeo4jFindNodesTool() {
|
|
|
3716
3752
|
limit: input.limit
|
|
3717
3753
|
}
|
|
3718
3754
|
};
|
|
3719
|
-
}
|
|
3720
|
-
await session.close();
|
|
3721
|
-
}
|
|
3755
|
+
});
|
|
3722
3756
|
} catch (error) {
|
|
3723
3757
|
return {
|
|
3724
3758
|
success: false,
|
|
@@ -3744,8 +3778,7 @@ function createNeo4jTraverseTool() {
|
|
|
3744
3778
|
try {
|
|
3745
3779
|
const safeDirection = validateDirection(input.direction || "outgoing");
|
|
3746
3780
|
const safeRelType = input.relationshipType ? validateRelationshipType(input.relationshipType) : null;
|
|
3747
|
-
|
|
3748
|
-
try {
|
|
3781
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3749
3782
|
let relPattern = "";
|
|
3750
3783
|
if (safeDirection === "OUTGOING") {
|
|
3751
3784
|
relPattern = safeRelType ? `-[r:${safeRelType}*1..${input.maxDepth}]->` : `-[r*1..${input.maxDepth}]->`;
|
|
@@ -3782,9 +3815,7 @@ function createNeo4jTraverseTool() {
|
|
|
3782
3815
|
maxDepth: input.maxDepth
|
|
3783
3816
|
}
|
|
3784
3817
|
};
|
|
3785
|
-
}
|
|
3786
|
-
await session.close();
|
|
3787
|
-
}
|
|
3818
|
+
});
|
|
3788
3819
|
} catch (error) {
|
|
3789
3820
|
return {
|
|
3790
3821
|
success: false,
|
|
@@ -3809,8 +3840,7 @@ function createNeo4jVectorSearchTool() {
|
|
|
3809
3840
|
};
|
|
3810
3841
|
}
|
|
3811
3842
|
try {
|
|
3812
|
-
|
|
3813
|
-
try {
|
|
3843
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3814
3844
|
const cypher = `
|
|
3815
3845
|
CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
|
|
3816
3846
|
YIELD node, score
|
|
@@ -3837,9 +3867,7 @@ function createNeo4jVectorSearchTool() {
|
|
|
3837
3867
|
limit: input.limit
|
|
3838
3868
|
}
|
|
3839
3869
|
};
|
|
3840
|
-
}
|
|
3841
|
-
await session.close();
|
|
3842
|
-
}
|
|
3870
|
+
});
|
|
3843
3871
|
} catch (error) {
|
|
3844
3872
|
const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search";
|
|
3845
3873
|
let helpText = "";
|
|
@@ -3885,8 +3913,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
|
|
|
3885
3913
|
});
|
|
3886
3914
|
try {
|
|
3887
3915
|
const embeddingResult = await embeddingManager.generateEmbedding(input.queryText, input.model);
|
|
3888
|
-
|
|
3889
|
-
try {
|
|
3916
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3890
3917
|
const cypher = `
|
|
3891
3918
|
CALL db.index.vector.queryNodes($indexName, $limit, $queryVector)
|
|
3892
3919
|
YIELD node, score
|
|
@@ -3928,9 +3955,7 @@ function createNeo4jVectorSearchWithEmbeddingTool() {
|
|
|
3928
3955
|
usage: embeddingResult.usage
|
|
3929
3956
|
}
|
|
3930
3957
|
};
|
|
3931
|
-
}
|
|
3932
|
-
await session.close();
|
|
3933
|
-
}
|
|
3958
|
+
});
|
|
3934
3959
|
} catch (error) {
|
|
3935
3960
|
const duration = Date.now() - startTime;
|
|
3936
3961
|
const errorMessage = error instanceof Error ? error.message : "Failed to perform vector search with embedding";
|
|
@@ -3986,8 +4011,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
|
|
|
3986
4011
|
const embeddingResult = await embeddingManager.generateEmbedding(textToEmbed, input.model);
|
|
3987
4012
|
const safeLabel = validateLabel(input.label);
|
|
3988
4013
|
const safeEmbeddingProp = validatePropertyKey(input.embeddingProperty || "embedding");
|
|
3989
|
-
|
|
3990
|
-
try {
|
|
4014
|
+
return await withNeo4jSession(input.database, async (session) => {
|
|
3991
4015
|
const allProperties = {
|
|
3992
4016
|
...input.properties
|
|
3993
4017
|
};
|
|
@@ -4021,9 +4045,7 @@ function createNeo4jCreateNodeWithEmbeddingTool() {
|
|
|
4021
4045
|
},
|
|
4022
4046
|
message: `Created node with label '${input.label}' and ${embeddingResult.dimensions}-dimensional embedding`
|
|
4023
4047
|
};
|
|
4024
|
-
}
|
|
4025
|
-
await session.close();
|
|
4026
|
-
}
|
|
4048
|
+
});
|
|
4027
4049
|
} catch (error) {
|
|
4028
4050
|
const errorMessage = error instanceof Error ? error.message : "Failed to create node with embedding";
|
|
4029
4051
|
let helpText = "";
|
|
@@ -7111,15 +7133,6 @@ function formatTableName(table) {
|
|
|
7111
7133
|
return table.schema ? `${table.schema}.${table.name}` : table.name;
|
|
7112
7134
|
}
|
|
7113
7135
|
|
|
7114
|
-
// src/data/relational/schema/type-mapper-normalization.ts
|
|
7115
|
-
function normaliseDbType(raw) {
|
|
7116
|
-
let type = raw.toLowerCase().trim();
|
|
7117
|
-
type = type.replace(/\[\]$/, "");
|
|
7118
|
-
type = type.replace(/\([\d,\s]+\)/, "");
|
|
7119
|
-
type = type.replace(/\s+unsigned$/, "");
|
|
7120
|
-
return type.trim();
|
|
7121
|
-
}
|
|
7122
|
-
|
|
7123
7136
|
// src/data/relational/schema/type-mapper-vendor-maps.ts
|
|
7124
7137
|
var POSTGRES_TYPE_MAP = {
|
|
7125
7138
|
smallint: "number",
|
|
@@ -7295,6 +7308,13 @@ function getVendorTypeMap(vendor) {
|
|
|
7295
7308
|
function usesStringPrecisionFallback(vendor, normalised) {
|
|
7296
7309
|
return (normalised === "bigint" || normalised === "int8" || normalised === "bigserial") && (vendor === "postgresql" || vendor === "mysql");
|
|
7297
7310
|
}
|
|
7311
|
+
function normaliseDbType(raw) {
|
|
7312
|
+
let type = raw.toLowerCase().trim();
|
|
7313
|
+
type = type.replace(/\[\]$/, "");
|
|
7314
|
+
type = type.replace(/\([\d,\s]+\)/, "");
|
|
7315
|
+
type = type.replace(/\s+unsigned$/, "");
|
|
7316
|
+
return type.trim();
|
|
7317
|
+
}
|
|
7298
7318
|
var logger14 = createLogger("agentforge:tools:data:relational:schema-diff");
|
|
7299
7319
|
function diffSchemas(before, after) {
|
|
7300
7320
|
const tableDiffs = [];
|
|
@@ -10310,49 +10330,57 @@ var fileSearchSchema = z.object({
|
|
|
10310
10330
|
recursive: z.boolean().default(true).describe("Search in subdirectories"),
|
|
10311
10331
|
caseSensitive: z.boolean().default(false).describe("Case-sensitive pattern matching")
|
|
10312
10332
|
});
|
|
10333
|
+
async function* traverseDirectory(directory, recursive) {
|
|
10334
|
+
const entries = await promises.readdir(directory, { withFileTypes: true });
|
|
10335
|
+
for (const entry of entries) {
|
|
10336
|
+
const fullPath = path.join(directory, entry.name);
|
|
10337
|
+
const isDirectory = entry.isDirectory();
|
|
10338
|
+
yield {
|
|
10339
|
+
name: entry.name,
|
|
10340
|
+
fullPath,
|
|
10341
|
+
isFile: entry.isFile(),
|
|
10342
|
+
isDirectory
|
|
10343
|
+
};
|
|
10344
|
+
if (recursive && isDirectory) {
|
|
10345
|
+
yield* traverseDirectory(fullPath, true);
|
|
10346
|
+
}
|
|
10347
|
+
}
|
|
10348
|
+
}
|
|
10349
|
+
|
|
10350
|
+
// src/file/directory/tools/directory-list.ts
|
|
10313
10351
|
function createDirectoryListTool(defaultRecursive = false, defaultIncludeDetails = false, policy = DEFAULT_FILE_SYSTEM_POLICY) {
|
|
10314
10352
|
return toolBuilder().name("directory-list").description("List all files and directories in a directory. Can optionally include file details and filter by extension.").category(ToolCategory.FILE_SYSTEM).tags(["directory", "list", "files", "filesystem"]).schema(directoryListSchema).implementSafe(async (input) => {
|
|
10315
10353
|
const safePath = await policy.resolvePath(input.path, "directory listing");
|
|
10316
10354
|
const includeDetails = input.includeDetails ?? defaultIncludeDetails;
|
|
10317
|
-
const
|
|
10318
|
-
|
|
10319
|
-
|
|
10320
|
-
|
|
10321
|
-
|
|
10322
|
-
|
|
10323
|
-
|
|
10324
|
-
if (!entry.isDirectory() || !recursive2) {
|
|
10325
|
-
continue;
|
|
10326
|
-
}
|
|
10327
|
-
}
|
|
10328
|
-
if (includeDetails) {
|
|
10329
|
-
const stats = await promises.lstat(fullPath);
|
|
10330
|
-
files2.push({
|
|
10331
|
-
name: entry.name,
|
|
10332
|
-
path: relativePath,
|
|
10333
|
-
fullPath,
|
|
10334
|
-
isFile: entry.isFile(),
|
|
10335
|
-
isDirectory: entry.isDirectory(),
|
|
10336
|
-
size: stats.size,
|
|
10337
|
-
modified: stats.mtime.toISOString()
|
|
10338
|
-
});
|
|
10339
|
-
} else {
|
|
10340
|
-
files2.push({
|
|
10341
|
-
name: entry.name,
|
|
10342
|
-
path: relativePath,
|
|
10343
|
-
isFile: entry.isFile(),
|
|
10344
|
-
isDirectory: entry.isDirectory()
|
|
10345
|
-
});
|
|
10346
|
-
}
|
|
10347
|
-
if (recursive2 && entry.isDirectory()) {
|
|
10348
|
-
const subFiles = await listFiles(fullPath, true);
|
|
10349
|
-
files2.push(...subFiles);
|
|
10355
|
+
const recursive = input.recursive ?? defaultRecursive;
|
|
10356
|
+
const files = [];
|
|
10357
|
+
for await (const entry of traverseDirectory(safePath, recursive)) {
|
|
10358
|
+
const relativePath = path.relative(safePath, entry.fullPath);
|
|
10359
|
+
if (input.extension && !entry.name.endsWith(input.extension)) {
|
|
10360
|
+
if (!entry.isDirectory || !recursive) {
|
|
10361
|
+
continue;
|
|
10350
10362
|
}
|
|
10351
10363
|
}
|
|
10352
|
-
|
|
10353
|
-
|
|
10354
|
-
|
|
10355
|
-
|
|
10364
|
+
if (includeDetails) {
|
|
10365
|
+
const stats = await promises.lstat(entry.fullPath);
|
|
10366
|
+
files.push({
|
|
10367
|
+
name: entry.name,
|
|
10368
|
+
path: relativePath,
|
|
10369
|
+
fullPath: entry.fullPath,
|
|
10370
|
+
isFile: entry.isFile,
|
|
10371
|
+
isDirectory: entry.isDirectory,
|
|
10372
|
+
size: stats.size,
|
|
10373
|
+
modified: stats.mtime.toISOString()
|
|
10374
|
+
});
|
|
10375
|
+
} else {
|
|
10376
|
+
files.push({
|
|
10377
|
+
name: entry.name,
|
|
10378
|
+
path: relativePath,
|
|
10379
|
+
isFile: entry.isFile,
|
|
10380
|
+
isDirectory: entry.isDirectory
|
|
10381
|
+
});
|
|
10382
|
+
}
|
|
10383
|
+
}
|
|
10356
10384
|
const result = {
|
|
10357
10385
|
path: input.path,
|
|
10358
10386
|
files,
|
|
@@ -10388,24 +10416,14 @@ function createFileSearchTool(defaultRecursive = true, defaultCaseSensitive = fa
|
|
|
10388
10416
|
const recursive = input.recursive ?? defaultRecursive;
|
|
10389
10417
|
const caseSensitive = input.caseSensitive ?? defaultCaseSensitive;
|
|
10390
10418
|
const safeDirectory = await policy.resolvePath(input.directory, "file search");
|
|
10391
|
-
const
|
|
10392
|
-
|
|
10393
|
-
|
|
10394
|
-
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
const fullPath = path.join(dir, entry.name);
|
|
10398
|
-
if (entry.isFile() && regex.test(entry.name)) {
|
|
10399
|
-
matches2.push(fullPath);
|
|
10400
|
-
}
|
|
10401
|
-
if (recursive && entry.isDirectory()) {
|
|
10402
|
-
const subMatches = await searchFiles(fullPath);
|
|
10403
|
-
matches2.push(...subMatches);
|
|
10404
|
-
}
|
|
10419
|
+
const regexPattern = input.pattern.replace(/\./g, "\\.").replace(/\*/g, ".*");
|
|
10420
|
+
const regex = new RegExp(`^${regexPattern}$`, caseSensitive ? "" : "i");
|
|
10421
|
+
const matches = [];
|
|
10422
|
+
for await (const entry of traverseDirectory(safeDirectory, recursive)) {
|
|
10423
|
+
if (entry.isFile && regex.test(entry.name)) {
|
|
10424
|
+
matches.push(entry.fullPath);
|
|
10405
10425
|
}
|
|
10406
|
-
|
|
10407
|
-
};
|
|
10408
|
-
const matches = await searchFiles(safeDirectory);
|
|
10426
|
+
}
|
|
10409
10427
|
return {
|
|
10410
10428
|
directory: input.directory,
|
|
10411
10429
|
pattern: input.pattern,
|
|
@@ -11367,11 +11385,11 @@ var AskHumanInputSchema = z.object({
|
|
|
11367
11385
|
});
|
|
11368
11386
|
var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || LogLevel.INFO;
|
|
11369
11387
|
var logger19 = createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
|
|
11370
|
-
function
|
|
11388
|
+
function isRecord4(value) {
|
|
11371
11389
|
return typeof value === "object" && value !== null;
|
|
11372
11390
|
}
|
|
11373
11391
|
function resolveInterrupt(module) {
|
|
11374
|
-
if (!
|
|
11392
|
+
if (!isRecord4(module)) {
|
|
11375
11393
|
return void 0;
|
|
11376
11394
|
}
|
|
11377
11395
|
const candidate = module.interrupt;
|