@agentforge/tools 0.16.13 → 0.16.14
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 +291 -267
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +0 -19
- package/dist/index.d.ts +0 -19
- package/dist/index.js +291 -267
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -815,7 +815,7 @@ function getDefaultSlackClient() {
|
|
|
815
815
|
}
|
|
816
816
|
};
|
|
817
817
|
}
|
|
818
|
-
function createSendSlackMessageTool(getSlackClient,
|
|
818
|
+
function createSendSlackMessageTool(getSlackClient, logger23) {
|
|
819
819
|
return core.toolBuilder().name("send-slack-message").description("Send a message to a Slack channel for team communication and notifications").category(core.ToolCategory.WEB).tags(["slack", "messaging", "communication"]).usageNotes(
|
|
820
820
|
"Use this for general team communication. For notifications with @mentions, consider using notify-slack instead. Use get-slack-channels first if you need to find the right channel."
|
|
821
821
|
).suggests(["get-slack-channels"]).schema(
|
|
@@ -824,7 +824,7 @@ function createSendSlackMessageTool(getSlackClient, logger22) {
|
|
|
824
824
|
message: zod.z.string().describe("Message content to send")
|
|
825
825
|
})
|
|
826
826
|
).implementSafe(async ({ channel, message }) => {
|
|
827
|
-
|
|
827
|
+
logger23.info("send-slack-message called", { channel, messageLength: message.length });
|
|
828
828
|
try {
|
|
829
829
|
const { client: slack, config } = getSlackClient();
|
|
830
830
|
const result = await slack.chat.postMessage({
|
|
@@ -833,7 +833,7 @@ function createSendSlackMessageTool(getSlackClient, logger22) {
|
|
|
833
833
|
username: config.botName,
|
|
834
834
|
icon_emoji: config.botIcon
|
|
835
835
|
});
|
|
836
|
-
|
|
836
|
+
logger23.info("send-slack-message result", {
|
|
837
837
|
...result.channel ? { channel: result.channel } : {},
|
|
838
838
|
...result.ts ? { timestamp: result.ts } : {},
|
|
839
839
|
messageLength: message.length,
|
|
@@ -846,7 +846,7 @@ function createSendSlackMessageTool(getSlackClient, logger22) {
|
|
|
846
846
|
message_id: result.ts
|
|
847
847
|
};
|
|
848
848
|
} catch (error) {
|
|
849
|
-
|
|
849
|
+
logger23.error("send-slack-message failed", {
|
|
850
850
|
channel,
|
|
851
851
|
error: error.message,
|
|
852
852
|
data: error.data
|
|
@@ -855,7 +855,7 @@ function createSendSlackMessageTool(getSlackClient, logger22) {
|
|
|
855
855
|
}
|
|
856
856
|
}).build();
|
|
857
857
|
}
|
|
858
|
-
function createNotifySlackTool(getSlackClient,
|
|
858
|
+
function createNotifySlackTool(getSlackClient, logger23) {
|
|
859
859
|
return core.toolBuilder().name("notify-slack").description("Send a notification to a Slack channel with optional @mentions for urgent alerts").category(core.ToolCategory.WEB).tags(["slack", "notification", "alert"]).usageNotes(
|
|
860
860
|
"Use this for urgent notifications that require @mentions. For general messages without mentions, use send-slack-message instead."
|
|
861
861
|
).suggests(["get-slack-channels"]).schema(
|
|
@@ -865,7 +865,7 @@ function createNotifySlackTool(getSlackClient, logger22) {
|
|
|
865
865
|
mentions: zod.z.array(zod.z.string()).optional().describe("List of usernames to mention (without @)")
|
|
866
866
|
})
|
|
867
867
|
).implementSafe(async ({ channel, message, mentions = [] }) => {
|
|
868
|
-
|
|
868
|
+
logger23.info("notify-slack called", {
|
|
869
869
|
channel,
|
|
870
870
|
messageLength: message.length,
|
|
871
871
|
mentionCount: mentions.length
|
|
@@ -879,7 +879,7 @@ function createNotifySlackTool(getSlackClient, logger22) {
|
|
|
879
879
|
username: config.botName,
|
|
880
880
|
icon_emoji: config.botIcon
|
|
881
881
|
});
|
|
882
|
-
|
|
882
|
+
logger23.info("notify-slack result", {
|
|
883
883
|
...result.channel ? { channel: result.channel } : {},
|
|
884
884
|
...result.ts ? { timestamp: result.ts } : {},
|
|
885
885
|
mentions: mentions.length
|
|
@@ -893,7 +893,7 @@ function createNotifySlackTool(getSlackClient, logger22) {
|
|
|
893
893
|
};
|
|
894
894
|
}).build();
|
|
895
895
|
}
|
|
896
|
-
function createGetSlackChannelsTool(getSlackClient,
|
|
896
|
+
function createGetSlackChannelsTool(getSlackClient, logger23) {
|
|
897
897
|
return core.toolBuilder().name("get-slack-channels").description("Get a list of available Slack channels to find the right channel for messaging").category(core.ToolCategory.WEB).tags(["slack", "channels", "list"]).usageNotes(
|
|
898
898
|
"Use this first to discover available channels before sending messages. Helps ensure you are sending to the correct channel."
|
|
899
899
|
).follows(["send-slack-message", "notify-slack"]).schema(
|
|
@@ -901,7 +901,7 @@ function createGetSlackChannelsTool(getSlackClient, logger22) {
|
|
|
901
901
|
include_private: zod.z.boolean().optional().describe("Include private channels (default: false)")
|
|
902
902
|
})
|
|
903
903
|
).implementSafe(async ({ include_private = false }) => {
|
|
904
|
-
|
|
904
|
+
logger23.info("get-slack-channels called", { include_private });
|
|
905
905
|
const { client: slack } = getSlackClient();
|
|
906
906
|
const publicChannels = await slack.conversations.list({
|
|
907
907
|
types: "public_channel",
|
|
@@ -915,7 +915,7 @@ function createGetSlackChannelsTool(getSlackClient, logger22) {
|
|
|
915
915
|
});
|
|
916
916
|
allChannels = [...allChannels, ...privateChannels.channels || []];
|
|
917
917
|
}
|
|
918
|
-
|
|
918
|
+
logger23.info("get-slack-channels result", {
|
|
919
919
|
channelCount: allChannels.length,
|
|
920
920
|
includePrivate: include_private
|
|
921
921
|
});
|
|
@@ -930,7 +930,7 @@ function createGetSlackChannelsTool(getSlackClient, logger22) {
|
|
|
930
930
|
};
|
|
931
931
|
}).build();
|
|
932
932
|
}
|
|
933
|
-
function createGetSlackMessagesTool(getSlackClient,
|
|
933
|
+
function createGetSlackMessagesTool(getSlackClient, logger23) {
|
|
934
934
|
return core.toolBuilder().name("get-slack-messages").description("Retrieve message history from a Slack channel to read recent conversations").category(core.ToolCategory.WEB).tags(["slack", "messages", "history", "read"]).usageNotes(
|
|
935
935
|
"Use this to read recent messages from a channel. Use get-slack-channels first if you need to find the channel ID. Returns messages in reverse chronological order (newest first)."
|
|
936
936
|
).suggests(["get-slack-channels"]).schema(
|
|
@@ -939,7 +939,7 @@ function createGetSlackMessagesTool(getSlackClient, logger22) {
|
|
|
939
939
|
limit: zod.z.number().int().min(1).max(100).optional().describe("Number of messages to retrieve (default: 20, max: 100)")
|
|
940
940
|
})
|
|
941
941
|
).implementSafe(async ({ channel, limit = 20 }) => {
|
|
942
|
-
|
|
942
|
+
logger23.info("get-slack-messages called", { channel, limit });
|
|
943
943
|
try {
|
|
944
944
|
const { client: slack } = getSlackClient();
|
|
945
945
|
let channelId = channel;
|
|
@@ -950,7 +950,7 @@ function createGetSlackMessagesTool(getSlackClient, logger22) {
|
|
|
950
950
|
});
|
|
951
951
|
const found = channels.channels?.find((c) => c.name === channel);
|
|
952
952
|
if (!found) {
|
|
953
|
-
|
|
953
|
+
logger23.error("get-slack-messages: channel not found", { channel });
|
|
954
954
|
throw new Error(
|
|
955
955
|
`Channel '${channel}' not found. Use get-slack-channels to see available channels.`
|
|
956
956
|
);
|
|
@@ -962,7 +962,7 @@ function createGetSlackMessagesTool(getSlackClient, logger22) {
|
|
|
962
962
|
limit: Math.min(limit, 100)
|
|
963
963
|
// Cap at 100 for performance
|
|
964
964
|
});
|
|
965
|
-
|
|
965
|
+
logger23.info("get-slack-messages result", {
|
|
966
966
|
channel: channelId,
|
|
967
967
|
messageCount: result.messages?.length || 0,
|
|
968
968
|
limit
|
|
@@ -980,7 +980,7 @@ function createGetSlackMessagesTool(getSlackClient, logger22) {
|
|
|
980
980
|
})) || []
|
|
981
981
|
};
|
|
982
982
|
} catch (error) {
|
|
983
|
-
|
|
983
|
+
logger23.error("get-slack-messages failed", {
|
|
984
984
|
channel,
|
|
985
985
|
error: error.message,
|
|
986
986
|
data: error.data
|
|
@@ -1061,12 +1061,12 @@ function getAuthHeader() {
|
|
|
1061
1061
|
const auth2 = Buffer.from(`${ATLASSIAN_EMAIL}:${ATLASSIAN_API_KEY}`).toString("base64");
|
|
1062
1062
|
return `Basic ${auth2}`;
|
|
1063
1063
|
}
|
|
1064
|
-
function createSearchConfluenceTool(getAuth, getAuthHeader2,
|
|
1064
|
+
function createSearchConfluenceTool(getAuth, getAuthHeader2, logger23) {
|
|
1065
1065
|
return core.toolBuilder().name("search-confluence").description("Search for pages in Confluence using keywords or CQL (Confluence Query Language). Returns matching pages with titles, IDs, and excerpts.").category(core.ToolCategory.WEB).tag("confluence").tag("search").tag("knowledge-base").usageNotes("Use this to find relevant documentation, policies, or information in Confluence. You can search by keywords or use CQL for advanced queries (e.g., 'space=AI AND type=page'). Use get-confluence-page to retrieve full content of specific pages.").suggests(["get-confluence-page"]).schema(zod.z.object({
|
|
1066
1066
|
query: zod.z.string().describe("Search query or CQL expression (e.g., 'payment processing' or 'space=BL3 AND title~payment')"),
|
|
1067
1067
|
limit: zod.z.number().optional().describe("Maximum number of results to return (default: 10, max: 25)")
|
|
1068
1068
|
})).implement(async ({ query, limit = 10 }) => {
|
|
1069
|
-
|
|
1069
|
+
logger23.info("search-confluence called", { query, limit });
|
|
1070
1070
|
try {
|
|
1071
1071
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1072
1072
|
const response = await axios16__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/search`, {
|
|
@@ -1091,13 +1091,13 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1091
1091
|
lastModified: page.version?.when || ""
|
|
1092
1092
|
}));
|
|
1093
1093
|
if (results.length === 0) {
|
|
1094
|
-
|
|
1094
|
+
logger23.warn("search-confluence returned NO RESULTS - this is a valid outcome, agent should not retry", {
|
|
1095
1095
|
query,
|
|
1096
1096
|
limit,
|
|
1097
1097
|
totalSize: response.data.totalSize
|
|
1098
1098
|
});
|
|
1099
1099
|
} else {
|
|
1100
|
-
|
|
1100
|
+
logger23.info("search-confluence result", {
|
|
1101
1101
|
query,
|
|
1102
1102
|
resultCount: results.length,
|
|
1103
1103
|
totalSize: response.data.totalSize,
|
|
@@ -1112,7 +1112,7 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1112
1112
|
results
|
|
1113
1113
|
});
|
|
1114
1114
|
} catch (error) {
|
|
1115
|
-
|
|
1115
|
+
logger23.error("search-confluence error", {
|
|
1116
1116
|
query,
|
|
1117
1117
|
error: error.response?.data?.message || error.message,
|
|
1118
1118
|
status: error.response?.status
|
|
@@ -1124,11 +1124,11 @@ function createSearchConfluenceTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1124
1124
|
}
|
|
1125
1125
|
}).build();
|
|
1126
1126
|
}
|
|
1127
|
-
function createGetConfluencePageTool(getAuth, getAuthHeader2,
|
|
1127
|
+
function createGetConfluencePageTool(getAuth, getAuthHeader2, logger23) {
|
|
1128
1128
|
return core.toolBuilder().name("get-confluence-page").description("Get the full content of a specific Confluence page by its ID. Returns the page title, content (in storage format), space, and metadata.").category(core.ToolCategory.WEB).tag("confluence").tag("page").tag("content").usageNotes("Use this after search-confluence to retrieve the full content of a specific page. The page ID can be found in search results.").requires(["search-confluence"]).schema(zod.z.object({
|
|
1129
1129
|
page_id: zod.z.string().describe("The Confluence page ID (from search results)")
|
|
1130
1130
|
})).implement(async ({ page_id }) => {
|
|
1131
|
-
|
|
1131
|
+
logger23.info("get-confluence-page called", { page_id });
|
|
1132
1132
|
try {
|
|
1133
1133
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1134
1134
|
const response = await axios16__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content/${page_id}`, {
|
|
@@ -1141,7 +1141,7 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1141
1141
|
}
|
|
1142
1142
|
});
|
|
1143
1143
|
const page = response.data;
|
|
1144
|
-
|
|
1144
|
+
logger23.info("get-confluence-page result", {
|
|
1145
1145
|
page_id,
|
|
1146
1146
|
title: page.title,
|
|
1147
1147
|
space: page.space?.name,
|
|
@@ -1163,7 +1163,7 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1163
1163
|
}
|
|
1164
1164
|
});
|
|
1165
1165
|
} catch (error) {
|
|
1166
|
-
|
|
1166
|
+
logger23.error("get-confluence-page error", {
|
|
1167
1167
|
page_id,
|
|
1168
1168
|
error: error.response?.data?.message || error.message,
|
|
1169
1169
|
status: error.response?.status
|
|
@@ -1175,11 +1175,11 @@ function createGetConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1175
1175
|
}
|
|
1176
1176
|
}).build();
|
|
1177
1177
|
}
|
|
1178
|
-
function createListConfluenceSpacesTool(getAuth, getAuthHeader2,
|
|
1178
|
+
function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger23) {
|
|
1179
1179
|
return core.toolBuilder().name("list-confluence-spaces").description("List all available Confluence spaces. Returns space names, keys, types, and descriptions to help identify where to search for information.").category(core.ToolCategory.WEB).tag("confluence").tag("spaces").tag("list").usageNotes("Use this first to discover available spaces before searching. Helps narrow down searches to specific areas (e.g., 'AI', 'BL3', 'Finance').").follows(["search-confluence"]).schema(zod.z.object({
|
|
1180
1180
|
limit: zod.z.number().optional().describe("Maximum number of spaces to return (default: 25)")
|
|
1181
1181
|
})).implement(async ({ limit = 25 }) => {
|
|
1182
|
-
|
|
1182
|
+
logger23.info("list-confluence-spaces called", { limit });
|
|
1183
1183
|
try {
|
|
1184
1184
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1185
1185
|
const response = await axios16__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/space`, {
|
|
@@ -1198,7 +1198,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1198
1198
|
description: space.description?.plain?.value || "",
|
|
1199
1199
|
url: `${ATLASSIAN_SITE_URL}/wiki${space._links.webui}`
|
|
1200
1200
|
}));
|
|
1201
|
-
|
|
1201
|
+
logger23.info("list-confluence-spaces result", {
|
|
1202
1202
|
spaceCount: spaces.length,
|
|
1203
1203
|
spaceKeys: spaces.map((s) => s.key).slice(0, 5)
|
|
1204
1204
|
// Log first 5 space keys
|
|
@@ -1209,7 +1209,7 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1209
1209
|
spaces
|
|
1210
1210
|
});
|
|
1211
1211
|
} catch (error) {
|
|
1212
|
-
|
|
1212
|
+
logger23.error("list-confluence-spaces error", {
|
|
1213
1213
|
error: error.response?.data?.message || error.message,
|
|
1214
1214
|
status: error.response?.status
|
|
1215
1215
|
});
|
|
@@ -1220,12 +1220,12 @@ function createListConfluenceSpacesTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1220
1220
|
}
|
|
1221
1221
|
}).build();
|
|
1222
1222
|
}
|
|
1223
|
-
function createGetSpacePagesTool(getAuth, getAuthHeader2,
|
|
1223
|
+
function createGetSpacePagesTool(getAuth, getAuthHeader2, logger23) {
|
|
1224
1224
|
return core.toolBuilder().name("get-space-pages").description("Get all pages from a specific Confluence space by space key. Useful for browsing content in a particular area.").category(core.ToolCategory.WEB).tag("confluence").tag("space").tag("pages").usageNotes("Use this to explore all pages in a specific space. Get the space key from list-confluence-spaces first.").requires(["list-confluence-spaces"]).schema(zod.z.object({
|
|
1225
1225
|
space_key: zod.z.string().describe("The space key (e.g., 'AI', 'BL3', 'FIN')"),
|
|
1226
1226
|
limit: zod.z.number().optional().describe("Maximum number of pages to return (default: 25)")
|
|
1227
1227
|
})).implement(async ({ space_key, limit = 25 }) => {
|
|
1228
|
-
|
|
1228
|
+
logger23.info("get-space-pages called", { space_key, limit });
|
|
1229
1229
|
try {
|
|
1230
1230
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1231
1231
|
const response = await axios16__default.default.get(`${ATLASSIAN_SITE_URL}/wiki/rest/api/content`, {
|
|
@@ -1247,12 +1247,12 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1247
1247
|
lastModified: page.version?.when || ""
|
|
1248
1248
|
}));
|
|
1249
1249
|
if (pages.length === 0) {
|
|
1250
|
-
|
|
1250
|
+
logger23.warn("get-space-pages returned NO PAGES - this is a valid outcome, agent should not retry", {
|
|
1251
1251
|
space_key,
|
|
1252
1252
|
limit
|
|
1253
1253
|
});
|
|
1254
1254
|
} else {
|
|
1255
|
-
|
|
1255
|
+
logger23.info("get-space-pages result", {
|
|
1256
1256
|
space_key,
|
|
1257
1257
|
pageCount: pages.length,
|
|
1258
1258
|
titles: pages.map((p) => p.title).slice(0, 3)
|
|
@@ -1266,7 +1266,7 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1266
1266
|
pages
|
|
1267
1267
|
});
|
|
1268
1268
|
} catch (error) {
|
|
1269
|
-
|
|
1269
|
+
logger23.error("get-space-pages error", {
|
|
1270
1270
|
space_key,
|
|
1271
1271
|
error: error.response?.data?.message || error.message,
|
|
1272
1272
|
status: error.response?.status
|
|
@@ -1278,14 +1278,14 @@ function createGetSpacePagesTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1278
1278
|
}
|
|
1279
1279
|
}).build();
|
|
1280
1280
|
}
|
|
1281
|
-
function createCreateConfluencePageTool(getAuth, getAuthHeader2,
|
|
1281
|
+
function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger23) {
|
|
1282
1282
|
return core.toolBuilder().name("create-confluence-page").description("Create a new page in a Confluence space. Requires space key, page title, and content (in HTML storage format).").category(core.ToolCategory.WEB).tag("confluence").tag("create").tag("write").usageNotes("Use this to create new documentation pages. Content should be in Confluence storage format (HTML). Get the space key from list-confluence-spaces first. Be mindful of creating duplicate pages.").requires(["list-confluence-spaces"]).schema(zod.z.object({
|
|
1283
1283
|
space_key: zod.z.string().describe("The space key where the page will be created (e.g., 'AI', 'BL3')"),
|
|
1284
1284
|
title: zod.z.string().describe("The title of the new page"),
|
|
1285
1285
|
content: zod.z.string().describe("The page content in HTML format (Confluence storage format)"),
|
|
1286
1286
|
parent_page_id: zod.z.string().optional().describe("Optional parent page ID to create this as a child page")
|
|
1287
1287
|
})).implement(async ({ space_key, title, content, parent_page_id }) => {
|
|
1288
|
-
|
|
1288
|
+
logger23.info("create-confluence-page called", { space_key, title, hasParent: !!parent_page_id });
|
|
1289
1289
|
try {
|
|
1290
1290
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1291
1291
|
const pageData = {
|
|
@@ -1312,7 +1312,7 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1312
1312
|
}
|
|
1313
1313
|
}
|
|
1314
1314
|
);
|
|
1315
|
-
|
|
1315
|
+
logger23.info("create-confluence-page result", {
|
|
1316
1316
|
page_id: response.data.id,
|
|
1317
1317
|
title: response.data.title,
|
|
1318
1318
|
space: space_key
|
|
@@ -1328,7 +1328,7 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1328
1328
|
}
|
|
1329
1329
|
});
|
|
1330
1330
|
} catch (error) {
|
|
1331
|
-
|
|
1331
|
+
logger23.error("create-confluence-page error", {
|
|
1332
1332
|
space_key,
|
|
1333
1333
|
title,
|
|
1334
1334
|
error: error.response?.data?.message || error.message,
|
|
@@ -1341,13 +1341,13 @@ function createCreateConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1341
1341
|
}
|
|
1342
1342
|
}).build();
|
|
1343
1343
|
}
|
|
1344
|
-
function createUpdateConfluencePageTool(getAuth, getAuthHeader2,
|
|
1344
|
+
function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger23) {
|
|
1345
1345
|
return core.toolBuilder().name("update-confluence-page").description("Update an existing Confluence page's content. Requires page ID, new title, and new content.").category(core.ToolCategory.WEB).tag("confluence").tag("update").tag("write").usageNotes("Use this to update existing documentation. You must provide the page ID (from search results). The tool will automatically handle version incrementing. Always get the current page content first to avoid overwriting important information.").requires(["get-confluence-page"]).schema(zod.z.object({
|
|
1346
1346
|
page_id: zod.z.string().describe("The ID of the page to update"),
|
|
1347
1347
|
title: zod.z.string().describe("The new title for the page"),
|
|
1348
1348
|
content: zod.z.string().describe("The new content in HTML format (Confluence storage format)")
|
|
1349
1349
|
})).implement(async ({ page_id, title, content }) => {
|
|
1350
|
-
|
|
1350
|
+
logger23.info("update-confluence-page called", { page_id, title });
|
|
1351
1351
|
try {
|
|
1352
1352
|
const { ATLASSIAN_SITE_URL } = getAuth();
|
|
1353
1353
|
const getResponse = await axios16__default.default.get(
|
|
@@ -1380,7 +1380,7 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1380
1380
|
}
|
|
1381
1381
|
}
|
|
1382
1382
|
);
|
|
1383
|
-
|
|
1383
|
+
logger23.info("update-confluence-page result", {
|
|
1384
1384
|
page_id,
|
|
1385
1385
|
title: updateResponse.data.title,
|
|
1386
1386
|
previousVersion: currentVersion,
|
|
@@ -1397,7 +1397,7 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1397
1397
|
}
|
|
1398
1398
|
});
|
|
1399
1399
|
} catch (error) {
|
|
1400
|
-
|
|
1400
|
+
logger23.error("update-confluence-page error", {
|
|
1401
1401
|
page_id,
|
|
1402
1402
|
title,
|
|
1403
1403
|
error: error.response?.data?.message || error.message,
|
|
@@ -1410,12 +1410,12 @@ function createUpdateConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1410
1410
|
}
|
|
1411
1411
|
}).build();
|
|
1412
1412
|
}
|
|
1413
|
-
function createArchiveConfluencePageTool(getAuth, getAuthHeader2,
|
|
1413
|
+
function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger23) {
|
|
1414
1414
|
return core.toolBuilder().name("archive-confluence-page").description("Archive a Confluence page by moving it to trash. The page can be restored by space admins. Note: UI may require a note explaining why the page was archived.").category(core.ToolCategory.WEB).tag("confluence").tag("archive").tag("delete").usageNotes("Use this to archive outdated or obsolete documentation. The page is moved to trash, not permanently deleted. Space admins can restore it if needed. Be very careful - only archive pages that are truly obsolete.").conflicts(["create-confluence-page"]).schema(zod.z.object({
|
|
1415
1415
|
page_id: zod.z.string().describe("The ID of the page to archive"),
|
|
1416
1416
|
reason: zod.z.string().optional().describe("Optional reason for archiving (for audit trail)")
|
|
1417
1417
|
})).implement(async ({ page_id, reason }) => {
|
|
1418
|
-
|
|
1418
|
+
logger23.info("archive-confluence-page called", {
|
|
1419
1419
|
page_id,
|
|
1420
1420
|
...reason ? { reason } : {}
|
|
1421
1421
|
});
|
|
@@ -1449,7 +1449,7 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1449
1449
|
}
|
|
1450
1450
|
}
|
|
1451
1451
|
);
|
|
1452
|
-
|
|
1452
|
+
logger23.info("archive-confluence-page result", {
|
|
1453
1453
|
page_id,
|
|
1454
1454
|
title: pageData.title,
|
|
1455
1455
|
previousVersion: currentVersion,
|
|
@@ -1467,7 +1467,7 @@ function createArchiveConfluencePageTool(getAuth, getAuthHeader2, logger22) {
|
|
|
1467
1467
|
}
|
|
1468
1468
|
});
|
|
1469
1469
|
} catch (error) {
|
|
1470
|
-
|
|
1470
|
+
logger23.error("archive-confluence-page error", {
|
|
1471
1471
|
page_id,
|
|
1472
1472
|
error: error.response?.data?.message || error.message,
|
|
1473
1473
|
status: error.response?.status
|
|
@@ -4044,15 +4044,14 @@ function quoteQualifiedIdentifier(qualifiedName, vendor) {
|
|
|
4044
4044
|
const parts = qualifiedName.split(".");
|
|
4045
4045
|
return parts.map((part) => quoteIdentifier(part, vendor)).join(".");
|
|
4046
4046
|
}
|
|
4047
|
-
var logger7 = core.createLogger("agentforge:tools:data:relational:connection");
|
|
4048
|
-
var
|
|
4049
|
-
|
|
4050
|
-
|
|
4051
|
-
|
|
4052
|
-
|
|
4053
|
-
|
|
4054
|
-
|
|
4055
|
-
})(ConnectionState || {});
|
|
4047
|
+
var logger7 = core.createLogger("agentforge:tools:data:relational:connection:vendor-init");
|
|
4048
|
+
var SAFE_INITIALIZATION_PATTERNS = [
|
|
4049
|
+
"Pool max connections must be",
|
|
4050
|
+
"Pool acquire timeout must be",
|
|
4051
|
+
"Pool idle timeout must be",
|
|
4052
|
+
"SQLite connection requires a url property",
|
|
4053
|
+
"Unsupported database vendor"
|
|
4054
|
+
];
|
|
4056
4055
|
function validatePoolConfig(poolConfig) {
|
|
4057
4056
|
if (poolConfig.max !== void 0 && poolConfig.max < 1) {
|
|
4058
4057
|
throw new Error("Pool max connections must be >= 1");
|
|
@@ -4064,13 +4063,150 @@ function validatePoolConfig(poolConfig) {
|
|
|
4064
4063
|
throw new Error("Pool idle timeout must be >= 0");
|
|
4065
4064
|
}
|
|
4066
4065
|
}
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4066
|
+
function pickConfiguredPoolFields(fields) {
|
|
4067
|
+
const configuredEntries = Object.entries(fields).filter(
|
|
4068
|
+
(entry) => entry[1] !== void 0
|
|
4069
|
+
);
|
|
4070
|
+
return Object.fromEntries(configuredEntries);
|
|
4071
|
+
}
|
|
4072
|
+
function normalizePostgreSQLConfig(connection) {
|
|
4073
|
+
const { pool: poolConfig, ...baseConfig } = typeof connection === "string" ? { connectionString: connection } : connection;
|
|
4074
|
+
if (poolConfig) {
|
|
4075
|
+
validatePoolConfig(poolConfig);
|
|
4076
|
+
}
|
|
4077
|
+
return {
|
|
4078
|
+
poolConfig,
|
|
4079
|
+
connectionConfig: {
|
|
4080
|
+
...baseConfig,
|
|
4081
|
+
...poolConfig?.max !== void 0 && { max: poolConfig.max },
|
|
4082
|
+
...poolConfig?.idleTimeoutMillis !== void 0 && {
|
|
4083
|
+
idleTimeoutMillis: poolConfig.idleTimeoutMillis
|
|
4084
|
+
},
|
|
4085
|
+
...poolConfig?.acquireTimeoutMillis !== void 0 && {
|
|
4086
|
+
connectionTimeoutMillis: poolConfig.acquireTimeoutMillis
|
|
4087
|
+
}
|
|
4088
|
+
}
|
|
4089
|
+
};
|
|
4090
|
+
}
|
|
4091
|
+
function normalizeMySQLConfig(connection) {
|
|
4092
|
+
if (typeof connection === "string") {
|
|
4093
|
+
logger7.debug("Creating MySQL connection pool from connection string", {
|
|
4094
|
+
vendor: "mysql"
|
|
4095
|
+
});
|
|
4096
|
+
return connection;
|
|
4097
|
+
}
|
|
4098
|
+
const { pool: poolConfig, ...baseConfig } = connection;
|
|
4099
|
+
if (poolConfig) {
|
|
4100
|
+
validatePoolConfig(poolConfig);
|
|
4101
|
+
}
|
|
4102
|
+
return {
|
|
4103
|
+
...baseConfig,
|
|
4104
|
+
...poolConfig?.max !== void 0 && { connectionLimit: poolConfig.max },
|
|
4105
|
+
...poolConfig?.acquireTimeoutMillis !== void 0 && {
|
|
4106
|
+
acquireTimeout: poolConfig.acquireTimeoutMillis
|
|
4107
|
+
},
|
|
4108
|
+
...poolConfig?.idleTimeoutMillis !== void 0 && {
|
|
4109
|
+
idleTimeout: poolConfig.idleTimeoutMillis
|
|
4110
|
+
}
|
|
4111
|
+
};
|
|
4112
|
+
}
|
|
4113
|
+
function resolveSqliteUrl(connection) {
|
|
4114
|
+
if (typeof connection === "string") {
|
|
4115
|
+
return { url: connection };
|
|
4116
|
+
}
|
|
4117
|
+
const { url, pool } = connection;
|
|
4118
|
+
if (!url) {
|
|
4119
|
+
throw new Error("SQLite connection requires a url property");
|
|
4120
|
+
}
|
|
4121
|
+
if (pool) {
|
|
4122
|
+
validatePoolConfig(pool);
|
|
4123
|
+
}
|
|
4124
|
+
return { url, poolConfig: pool };
|
|
4125
|
+
}
|
|
4126
|
+
async function initializeVendorConnection(config) {
|
|
4127
|
+
switch (config.vendor) {
|
|
4128
|
+
case "postgresql":
|
|
4129
|
+
return initializePostgreSQLConnection(config.connection);
|
|
4130
|
+
case "mysql":
|
|
4131
|
+
return initializeMySQLConnection(config.connection);
|
|
4132
|
+
case "sqlite":
|
|
4133
|
+
return initializeSQLiteConnection(config.connection);
|
|
4134
|
+
default:
|
|
4135
|
+
throw new Error(`Unsupported database vendor: ${config.vendor}`);
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
async function initializePostgreSQLConnection(connection) {
|
|
4139
|
+
const { drizzle } = await import('drizzle-orm/node-postgres');
|
|
4140
|
+
const { Pool } = await import('pg');
|
|
4141
|
+
const { connectionConfig } = normalizePostgreSQLConfig(connection);
|
|
4142
|
+
logger7.debug("Creating PostgreSQL connection pool", {
|
|
4143
|
+
vendor: "postgresql",
|
|
4144
|
+
poolConfig: pickConfiguredPoolFields({
|
|
4145
|
+
max: connectionConfig.max,
|
|
4146
|
+
idleTimeoutMillis: connectionConfig.idleTimeoutMillis,
|
|
4147
|
+
connectionTimeoutMillis: connectionConfig.connectionTimeoutMillis
|
|
4148
|
+
})
|
|
4149
|
+
});
|
|
4150
|
+
const client = new Pool(connectionConfig);
|
|
4151
|
+
const db = drizzle({ client });
|
|
4152
|
+
return { client, db };
|
|
4153
|
+
}
|
|
4154
|
+
async function initializeMySQLConnection(connection) {
|
|
4155
|
+
const { drizzle } = await import('drizzle-orm/mysql2');
|
|
4156
|
+
const mysql = await import('mysql2/promise');
|
|
4157
|
+
const connectionConfig = normalizeMySQLConfig(connection);
|
|
4158
|
+
if (typeof connectionConfig !== "string") {
|
|
4159
|
+
logger7.debug("Creating MySQL connection pool", {
|
|
4160
|
+
vendor: "mysql",
|
|
4161
|
+
poolConfig: pickConfiguredPoolFields({
|
|
4162
|
+
connectionLimit: connectionConfig.connectionLimit,
|
|
4163
|
+
acquireTimeout: connectionConfig.acquireTimeout,
|
|
4164
|
+
idleTimeout: connectionConfig.idleTimeout
|
|
4165
|
+
})
|
|
4166
|
+
});
|
|
4167
|
+
}
|
|
4168
|
+
let client;
|
|
4169
|
+
if (typeof connectionConfig === "string") {
|
|
4170
|
+
client = mysql.createPool(connectionConfig);
|
|
4171
|
+
} else {
|
|
4172
|
+
client = mysql.createPool(connectionConfig);
|
|
4173
|
+
}
|
|
4174
|
+
const db = drizzle({ client });
|
|
4175
|
+
return { client, db };
|
|
4176
|
+
}
|
|
4177
|
+
async function initializeSQLiteConnection(connection) {
|
|
4178
|
+
const { drizzle } = await import('drizzle-orm/better-sqlite3');
|
|
4179
|
+
const DatabaseModule = await import('better-sqlite3');
|
|
4180
|
+
const Database = DatabaseModule.default;
|
|
4181
|
+
const { url, poolConfig } = resolveSqliteUrl(connection);
|
|
4182
|
+
if (poolConfig) {
|
|
4183
|
+
logger7.debug("SQLite pool configuration provided but not applied (SQLite uses single connection)", {
|
|
4184
|
+
vendor: "sqlite",
|
|
4185
|
+
poolConfig: pickConfiguredPoolFields({
|
|
4186
|
+
max: poolConfig.max,
|
|
4187
|
+
idleTimeoutMillis: poolConfig.idleTimeoutMillis,
|
|
4188
|
+
acquireTimeoutMillis: poolConfig.acquireTimeoutMillis
|
|
4189
|
+
})
|
|
4190
|
+
});
|
|
4191
|
+
}
|
|
4192
|
+
logger7.debug("Creating SQLite connection", {
|
|
4193
|
+
vendor: "sqlite",
|
|
4194
|
+
url: url === ":memory:" ? ":memory:" : "file"
|
|
4195
|
+
});
|
|
4196
|
+
const client = new Database(url);
|
|
4197
|
+
client.pragma("foreign_keys = ON");
|
|
4198
|
+
const db = drizzle({ client });
|
|
4199
|
+
return { client, db };
|
|
4200
|
+
}
|
|
4201
|
+
var logger8 = core.createLogger("agentforge:tools:data:relational:connection");
|
|
4202
|
+
var ConnectionState = /* @__PURE__ */ ((ConnectionState2) => {
|
|
4203
|
+
ConnectionState2["DISCONNECTED"] = "disconnected";
|
|
4204
|
+
ConnectionState2["CONNECTING"] = "connecting";
|
|
4205
|
+
ConnectionState2["CONNECTED"] = "connected";
|
|
4206
|
+
ConnectionState2["RECONNECTING"] = "reconnecting";
|
|
4207
|
+
ConnectionState2["ERROR"] = "error";
|
|
4208
|
+
return ConnectionState2;
|
|
4209
|
+
})(ConnectionState || {});
|
|
4074
4210
|
var ConnectionManager = class extends events.EventEmitter {
|
|
4075
4211
|
vendor;
|
|
4076
4212
|
db;
|
|
@@ -4110,18 +4246,18 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4110
4246
|
*/
|
|
4111
4247
|
async connect() {
|
|
4112
4248
|
if (this.state === "connected" /* CONNECTED */) {
|
|
4113
|
-
|
|
4249
|
+
logger8.debug("Already connected", { vendor: this.vendor });
|
|
4114
4250
|
return;
|
|
4115
4251
|
}
|
|
4116
4252
|
if (this.connectPromise) {
|
|
4117
|
-
|
|
4253
|
+
logger8.debug("Connection already in progress, waiting for completion", {
|
|
4118
4254
|
vendor: this.vendor,
|
|
4119
4255
|
state: this.state
|
|
4120
4256
|
});
|
|
4121
4257
|
return this.connectPromise;
|
|
4122
4258
|
}
|
|
4123
4259
|
if (this.reconnectionTimer) {
|
|
4124
|
-
|
|
4260
|
+
logger8.debug("Clearing pending reconnection timer before manual connect", {
|
|
4125
4261
|
vendor: this.vendor
|
|
4126
4262
|
});
|
|
4127
4263
|
clearTimeout(this.reconnectionTimer);
|
|
@@ -4147,7 +4283,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4147
4283
|
}
|
|
4148
4284
|
this.reconnectionAttempts = 0;
|
|
4149
4285
|
if (this.connectPromise) {
|
|
4150
|
-
|
|
4286
|
+
logger8.debug("Waiting for in-flight connection attempt to complete before disconnect", {
|
|
4151
4287
|
vendor: this.vendor
|
|
4152
4288
|
});
|
|
4153
4289
|
try {
|
|
@@ -4200,7 +4336,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4200
4336
|
const startTime = Date.now();
|
|
4201
4337
|
const currentGeneration = this.connectionGeneration;
|
|
4202
4338
|
if (this.state === "connected" /* CONNECTED */ && this.client) {
|
|
4203
|
-
|
|
4339
|
+
logger8.warn("Re-initializing an already connected manager; emitting disconnected before cleanup", {
|
|
4204
4340
|
vendor: this.vendor
|
|
4205
4341
|
});
|
|
4206
4342
|
this.setState("disconnected" /* DISCONNECTED */);
|
|
@@ -4208,27 +4344,17 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4208
4344
|
await this.cleanupCancelledConnection();
|
|
4209
4345
|
}
|
|
4210
4346
|
this.setState("connecting" /* CONNECTING */);
|
|
4211
|
-
|
|
4347
|
+
logger8.info("Initializing database connection", {
|
|
4212
4348
|
vendor: this.vendor,
|
|
4213
4349
|
connectionType: typeof this.config.connection,
|
|
4214
4350
|
state: this.state
|
|
4215
4351
|
});
|
|
4216
4352
|
try {
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
break;
|
|
4221
|
-
case "mysql":
|
|
4222
|
-
await this.initializeMySQL();
|
|
4223
|
-
break;
|
|
4224
|
-
case "sqlite":
|
|
4225
|
-
await this.initializeSQLite();
|
|
4226
|
-
break;
|
|
4227
|
-
default:
|
|
4228
|
-
throw new Error(`Unsupported database vendor: ${this.vendor}`);
|
|
4229
|
-
}
|
|
4353
|
+
const initialized = await initializeVendorConnection(this.config);
|
|
4354
|
+
this.client = initialized.client;
|
|
4355
|
+
this.db = initialized.db;
|
|
4230
4356
|
if (currentGeneration !== this.connectionGeneration) {
|
|
4231
|
-
|
|
4357
|
+
logger8.debug("Connection cancelled during initialization", {
|
|
4232
4358
|
vendor: this.vendor,
|
|
4233
4359
|
currentGeneration,
|
|
4234
4360
|
newGeneration: this.connectionGeneration
|
|
@@ -4237,13 +4363,13 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4237
4363
|
this.setState("disconnected" /* DISCONNECTED */);
|
|
4238
4364
|
throw new Error("Connection cancelled during initialization");
|
|
4239
4365
|
}
|
|
4240
|
-
|
|
4366
|
+
logger8.debug("Validating connection health", { vendor: this.vendor });
|
|
4241
4367
|
const healthy = await this.isHealthy();
|
|
4242
4368
|
if (!healthy) {
|
|
4243
4369
|
throw new Error(`Failed to establish healthy connection to ${this.vendor} database`);
|
|
4244
4370
|
}
|
|
4245
4371
|
if (currentGeneration !== this.connectionGeneration) {
|
|
4246
|
-
|
|
4372
|
+
logger8.debug("Connection cancelled during health check", {
|
|
4247
4373
|
vendor: this.vendor,
|
|
4248
4374
|
currentGeneration,
|
|
4249
4375
|
newGeneration: this.connectionGeneration
|
|
@@ -4255,7 +4381,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4255
4381
|
this.setState("connected" /* CONNECTED */);
|
|
4256
4382
|
this.emit("connected");
|
|
4257
4383
|
this.reconnectionAttempts = 0;
|
|
4258
|
-
|
|
4384
|
+
logger8.info("Database connection initialized successfully", {
|
|
4259
4385
|
vendor: this.vendor,
|
|
4260
4386
|
duration: Date.now() - startTime,
|
|
4261
4387
|
state: this.state
|
|
@@ -4276,7 +4402,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4276
4402
|
if (this.listenerCount("error") > 0) {
|
|
4277
4403
|
this.emit("error", normalizedError);
|
|
4278
4404
|
}
|
|
4279
|
-
|
|
4405
|
+
logger8.error(errorMessage, {
|
|
4280
4406
|
vendor: this.vendor,
|
|
4281
4407
|
error: normalizedError.message,
|
|
4282
4408
|
duration: Date.now() - startTime,
|
|
@@ -4287,7 +4413,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4287
4413
|
this.scheduleReconnection();
|
|
4288
4414
|
}
|
|
4289
4415
|
} else {
|
|
4290
|
-
|
|
4416
|
+
logger8.debug("Connection initialization cancelled", {
|
|
4291
4417
|
vendor: this.vendor,
|
|
4292
4418
|
duration: Date.now() - startTime,
|
|
4293
4419
|
state: this.state
|
|
@@ -4308,7 +4434,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4308
4434
|
const oldState = this.state;
|
|
4309
4435
|
this.state = newState;
|
|
4310
4436
|
if (oldState !== newState) {
|
|
4311
|
-
|
|
4437
|
+
logger8.debug("Connection state changed", {
|
|
4312
4438
|
vendor: this.vendor,
|
|
4313
4439
|
oldState,
|
|
4314
4440
|
newState
|
|
@@ -4321,7 +4447,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4321
4447
|
*/
|
|
4322
4448
|
scheduleReconnection() {
|
|
4323
4449
|
if (this.reconnectionConfig.maxAttempts > 0 && this.reconnectionAttempts >= this.reconnectionConfig.maxAttempts) {
|
|
4324
|
-
|
|
4450
|
+
logger8.error("Max reconnection attempts reached", {
|
|
4325
4451
|
vendor: this.vendor,
|
|
4326
4452
|
attempts: this.reconnectionAttempts,
|
|
4327
4453
|
maxAttempts: this.reconnectionConfig.maxAttempts
|
|
@@ -4334,7 +4460,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4334
4460
|
);
|
|
4335
4461
|
this.reconnectionAttempts++;
|
|
4336
4462
|
this.setState("reconnecting" /* RECONNECTING */);
|
|
4337
|
-
|
|
4463
|
+
logger8.info("Scheduling reconnection attempt", {
|
|
4338
4464
|
vendor: this.vendor,
|
|
4339
4465
|
attempt: this.reconnectionAttempts,
|
|
4340
4466
|
maxAttempts: this.reconnectionConfig.maxAttempts,
|
|
@@ -4348,7 +4474,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4348
4474
|
this.reconnectionTimer = setTimeout(async () => {
|
|
4349
4475
|
this.reconnectionTimer = null;
|
|
4350
4476
|
try {
|
|
4351
|
-
|
|
4477
|
+
logger8.info("Attempting reconnection", {
|
|
4352
4478
|
vendor: this.vendor,
|
|
4353
4479
|
attempt: this.reconnectionAttempts
|
|
4354
4480
|
});
|
|
@@ -4357,7 +4483,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4357
4483
|
});
|
|
4358
4484
|
await this.connectPromise;
|
|
4359
4485
|
} catch (error) {
|
|
4360
|
-
|
|
4486
|
+
logger8.error("Reconnection attempt failed", {
|
|
4361
4487
|
vendor: this.vendor,
|
|
4362
4488
|
attempt: this.reconnectionAttempts,
|
|
4363
4489
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -4365,108 +4491,6 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4365
4491
|
}
|
|
4366
4492
|
}, delay2);
|
|
4367
4493
|
}
|
|
4368
|
-
/**
|
|
4369
|
-
* Initialize PostgreSQL connection using Drizzle ORM with node-postgres
|
|
4370
|
-
*
|
|
4371
|
-
* Applies pool configuration options to pg.Pool for connection management.
|
|
4372
|
-
*/
|
|
4373
|
-
async initializePostgreSQL() {
|
|
4374
|
-
const { drizzle } = await import('drizzle-orm/node-postgres');
|
|
4375
|
-
const { Pool } = await import('pg');
|
|
4376
|
-
const { pool: poolConfig, ...baseConfig } = typeof this.config.connection === "string" ? { connectionString: this.config.connection } : this.config.connection;
|
|
4377
|
-
if (poolConfig) {
|
|
4378
|
-
validatePoolConfig(poolConfig);
|
|
4379
|
-
}
|
|
4380
|
-
const connectionConfig = {
|
|
4381
|
-
...baseConfig,
|
|
4382
|
-
// Map our PoolConfig to pg.Pool options
|
|
4383
|
-
// Note: pg.Pool does not support a `min` option
|
|
4384
|
-
...poolConfig?.max !== void 0 && { max: poolConfig.max },
|
|
4385
|
-
...poolConfig?.idleTimeoutMillis !== void 0 && { idleTimeoutMillis: poolConfig.idleTimeoutMillis },
|
|
4386
|
-
...poolConfig?.acquireTimeoutMillis !== void 0 && { connectionTimeoutMillis: poolConfig.acquireTimeoutMillis }
|
|
4387
|
-
};
|
|
4388
|
-
logger7.debug("Creating PostgreSQL connection pool", {
|
|
4389
|
-
vendor: this.vendor,
|
|
4390
|
-
poolConfig: {
|
|
4391
|
-
...connectionConfig.max !== void 0 ? { max: connectionConfig.max } : {},
|
|
4392
|
-
...connectionConfig.idleTimeoutMillis !== void 0 ? { idleTimeoutMillis: connectionConfig.idleTimeoutMillis } : {},
|
|
4393
|
-
...connectionConfig.connectionTimeoutMillis !== void 0 ? { connectionTimeoutMillis: connectionConfig.connectionTimeoutMillis } : {}
|
|
4394
|
-
}
|
|
4395
|
-
});
|
|
4396
|
-
this.client = new Pool(connectionConfig);
|
|
4397
|
-
this.db = drizzle({ client: this.client });
|
|
4398
|
-
}
|
|
4399
|
-
/**
|
|
4400
|
-
* Initialize MySQL connection using Drizzle ORM with mysql2
|
|
4401
|
-
*
|
|
4402
|
-
* Applies pool configuration options to mysql2.createPool for connection management.
|
|
4403
|
-
*/
|
|
4404
|
-
async initializeMySQL() {
|
|
4405
|
-
const { drizzle } = await import('drizzle-orm/mysql2');
|
|
4406
|
-
const mysql = await import('mysql2/promise');
|
|
4407
|
-
let connectionConfig;
|
|
4408
|
-
if (typeof this.config.connection === "string") {
|
|
4409
|
-
connectionConfig = this.config.connection;
|
|
4410
|
-
logger7.debug("Creating MySQL connection pool from connection string", {
|
|
4411
|
-
vendor: this.vendor
|
|
4412
|
-
});
|
|
4413
|
-
} else {
|
|
4414
|
-
const { pool: poolConfig, ...baseConfig } = this.config.connection;
|
|
4415
|
-
if (poolConfig) {
|
|
4416
|
-
validatePoolConfig(poolConfig);
|
|
4417
|
-
}
|
|
4418
|
-
connectionConfig = {
|
|
4419
|
-
...baseConfig,
|
|
4420
|
-
// Map our PoolConfig to mysql2 pool options
|
|
4421
|
-
...poolConfig?.max !== void 0 && { connectionLimit: poolConfig.max },
|
|
4422
|
-
...poolConfig?.acquireTimeoutMillis !== void 0 && { acquireTimeout: poolConfig.acquireTimeoutMillis },
|
|
4423
|
-
...poolConfig?.idleTimeoutMillis !== void 0 && { idleTimeout: poolConfig.idleTimeoutMillis }
|
|
4424
|
-
};
|
|
4425
|
-
logger7.debug("Creating MySQL connection pool", {
|
|
4426
|
-
vendor: this.vendor,
|
|
4427
|
-
poolConfig: {
|
|
4428
|
-
...connectionConfig.connectionLimit !== void 0 ? { connectionLimit: connectionConfig.connectionLimit } : {},
|
|
4429
|
-
...connectionConfig.acquireTimeout !== void 0 ? { acquireTimeout: connectionConfig.acquireTimeout } : {},
|
|
4430
|
-
...connectionConfig.idleTimeout !== void 0 ? { idleTimeout: connectionConfig.idleTimeout } : {}
|
|
4431
|
-
}
|
|
4432
|
-
});
|
|
4433
|
-
}
|
|
4434
|
-
this.client = mysql.createPool(connectionConfig);
|
|
4435
|
-
this.db = drizzle({ client: this.client });
|
|
4436
|
-
}
|
|
4437
|
-
/**
|
|
4438
|
-
* Initialize SQLite connection using Drizzle ORM with better-sqlite3
|
|
4439
|
-
*
|
|
4440
|
-
* Note: SQLite uses a single connection. Pool configuration is logged but not applied
|
|
4441
|
-
* as SQLite handles concurrent access through its internal locking mechanism.
|
|
4442
|
-
*/
|
|
4443
|
-
async initializeSQLite() {
|
|
4444
|
-
const { drizzle } = await import('drizzle-orm/better-sqlite3');
|
|
4445
|
-
const DatabaseModule = await import('better-sqlite3');
|
|
4446
|
-
const Database = DatabaseModule.default;
|
|
4447
|
-
const url = typeof this.config.connection === "string" ? this.config.connection : this.config.connection.url;
|
|
4448
|
-
if (!url) {
|
|
4449
|
-
throw new Error("SQLite connection requires a url property");
|
|
4450
|
-
}
|
|
4451
|
-
if (typeof this.config.connection === "object" && this.config.connection.pool) {
|
|
4452
|
-
validatePoolConfig(this.config.connection.pool);
|
|
4453
|
-
logger7.debug("SQLite pool configuration provided but not applied (SQLite uses single connection)", {
|
|
4454
|
-
vendor: this.vendor,
|
|
4455
|
-
poolConfig: {
|
|
4456
|
-
...this.config.connection.pool.max !== void 0 ? { max: this.config.connection.pool.max } : {},
|
|
4457
|
-
...this.config.connection.pool.idleTimeoutMillis !== void 0 ? { idleTimeoutMillis: this.config.connection.pool.idleTimeoutMillis } : {},
|
|
4458
|
-
...this.config.connection.pool.acquireTimeoutMillis !== void 0 ? { acquireTimeoutMillis: this.config.connection.pool.acquireTimeoutMillis } : {}
|
|
4459
|
-
}
|
|
4460
|
-
});
|
|
4461
|
-
}
|
|
4462
|
-
logger7.debug("Creating SQLite connection", {
|
|
4463
|
-
vendor: this.vendor,
|
|
4464
|
-
url: url === ":memory:" ? ":memory:" : "file"
|
|
4465
|
-
});
|
|
4466
|
-
this.client = new Database(url);
|
|
4467
|
-
this.client.pragma("foreign_keys = ON");
|
|
4468
|
-
this.db = drizzle({ client: this.client });
|
|
4469
|
-
}
|
|
4470
4494
|
/**
|
|
4471
4495
|
* Determine whether an error thrown by drizzle-orm's better-sqlite3 adapter
|
|
4472
4496
|
* `.all()` indicates the statement does not return data (i.e. it is DML/DDL,
|
|
@@ -4505,7 +4529,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4505
4529
|
if (!this.db) {
|
|
4506
4530
|
throw new Error("Database not initialized. Call initialize() first.");
|
|
4507
4531
|
}
|
|
4508
|
-
|
|
4532
|
+
logger8.debug("Executing SQL query", {
|
|
4509
4533
|
vendor: this.vendor
|
|
4510
4534
|
});
|
|
4511
4535
|
if (this.vendor === "sqlite") {
|
|
@@ -4636,14 +4660,14 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4636
4660
|
async close() {
|
|
4637
4661
|
this.connectionGeneration++;
|
|
4638
4662
|
if (this.reconnectionTimer) {
|
|
4639
|
-
|
|
4663
|
+
logger8.debug("Canceling pending reconnection timer during close", {
|
|
4640
4664
|
vendor: this.vendor
|
|
4641
4665
|
});
|
|
4642
4666
|
clearTimeout(this.reconnectionTimer);
|
|
4643
4667
|
this.reconnectionTimer = null;
|
|
4644
4668
|
}
|
|
4645
4669
|
if (this.connectPromise) {
|
|
4646
|
-
|
|
4670
|
+
logger8.debug("Waiting for in-flight connection attempt to complete before close", {
|
|
4647
4671
|
vendor: this.vendor
|
|
4648
4672
|
});
|
|
4649
4673
|
try {
|
|
@@ -4653,7 +4677,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4653
4677
|
this.connectPromise = null;
|
|
4654
4678
|
}
|
|
4655
4679
|
if (this.client) {
|
|
4656
|
-
|
|
4680
|
+
logger8.info("Closing database connection", {
|
|
4657
4681
|
vendor: this.vendor,
|
|
4658
4682
|
state: this.state
|
|
4659
4683
|
});
|
|
@@ -4665,12 +4689,12 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4665
4689
|
}
|
|
4666
4690
|
this.setState("disconnected" /* DISCONNECTED */);
|
|
4667
4691
|
this.emit("disconnected");
|
|
4668
|
-
|
|
4692
|
+
logger8.debug("Database connection closed successfully", {
|
|
4669
4693
|
vendor: this.vendor,
|
|
4670
4694
|
state: this.state
|
|
4671
4695
|
});
|
|
4672
4696
|
} catch (error) {
|
|
4673
|
-
|
|
4697
|
+
logger8.error("Error closing database connection", {
|
|
4674
4698
|
vendor: this.vendor,
|
|
4675
4699
|
error: error instanceof Error ? error.message : String(error),
|
|
4676
4700
|
state: this.state
|
|
@@ -4695,7 +4719,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4695
4719
|
if (!this.client) {
|
|
4696
4720
|
return;
|
|
4697
4721
|
}
|
|
4698
|
-
|
|
4722
|
+
logger8.debug("Cleaning up cancelled connection", {
|
|
4699
4723
|
vendor: this.vendor
|
|
4700
4724
|
});
|
|
4701
4725
|
try {
|
|
@@ -4705,7 +4729,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4705
4729
|
this.client.close();
|
|
4706
4730
|
}
|
|
4707
4731
|
} catch (error) {
|
|
4708
|
-
|
|
4732
|
+
logger8.debug("Error during cancelled connection cleanup", {
|
|
4709
4733
|
vendor: this.vendor,
|
|
4710
4734
|
error: error instanceof Error ? error.message : String(error)
|
|
4711
4735
|
});
|
|
@@ -4720,15 +4744,15 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4720
4744
|
*/
|
|
4721
4745
|
async isHealthy() {
|
|
4722
4746
|
if (!this.db || !this.client) {
|
|
4723
|
-
|
|
4747
|
+
logger8.debug("Health check failed: connection not initialized", { vendor: this.vendor });
|
|
4724
4748
|
return false;
|
|
4725
4749
|
}
|
|
4726
4750
|
try {
|
|
4727
4751
|
await this.execute(drizzleOrm.sql`SELECT 1`);
|
|
4728
|
-
|
|
4752
|
+
logger8.debug("Health check passed", { vendor: this.vendor });
|
|
4729
4753
|
return true;
|
|
4730
4754
|
} catch (error) {
|
|
4731
|
-
|
|
4755
|
+
logger8.debug("Health check failed", {
|
|
4732
4756
|
vendor: this.vendor,
|
|
4733
4757
|
error: error instanceof Error ? error.message : String(error)
|
|
4734
4758
|
});
|
|
@@ -4736,7 +4760,7 @@ var ConnectionManager = class extends events.EventEmitter {
|
|
|
4736
4760
|
}
|
|
4737
4761
|
}
|
|
4738
4762
|
};
|
|
4739
|
-
var
|
|
4763
|
+
var logger9 = core.createLogger("agentforge:tools:data:relational:query");
|
|
4740
4764
|
function buildParameterizedQuery(sqlString, params) {
|
|
4741
4765
|
if (!params) {
|
|
4742
4766
|
return drizzleOrm.sql.raw(sqlString);
|
|
@@ -4811,7 +4835,7 @@ function buildParameterizedQuery(sqlString, params) {
|
|
|
4811
4835
|
}
|
|
4812
4836
|
async function executeQuery(manager, input, context) {
|
|
4813
4837
|
const startTime = Date.now();
|
|
4814
|
-
|
|
4838
|
+
logger9.debug("Executing query", {
|
|
4815
4839
|
vendor: input.vendor,
|
|
4816
4840
|
hasParams: !!input.params,
|
|
4817
4841
|
paramCount: input.params ? Array.isArray(input.params) ? input.params.length : Object.keys(input.params).length : 0
|
|
@@ -4825,7 +4849,7 @@ async function executeQuery(manager, input, context) {
|
|
|
4825
4849
|
const executionTime = Date.now() - startTime;
|
|
4826
4850
|
const rows = Array.isArray(result) ? result : result.rows || [];
|
|
4827
4851
|
const rowCount = result.rowCount || result.affectedRows || rows.length;
|
|
4828
|
-
|
|
4852
|
+
logger9.debug("Query executed successfully", {
|
|
4829
4853
|
vendor: input.vendor,
|
|
4830
4854
|
rowCount,
|
|
4831
4855
|
executionTime
|
|
@@ -4837,7 +4861,7 @@ async function executeQuery(manager, input, context) {
|
|
|
4837
4861
|
};
|
|
4838
4862
|
} catch (error) {
|
|
4839
4863
|
const executionTime = Date.now() - startTime;
|
|
4840
|
-
|
|
4864
|
+
logger9.error("Query execution failed", {
|
|
4841
4865
|
vendor: input.vendor,
|
|
4842
4866
|
error: error instanceof Error ? error.message : String(error),
|
|
4843
4867
|
executionTime
|
|
@@ -5261,7 +5285,7 @@ function buildSelectQuery(input) {
|
|
|
5261
5285
|
}
|
|
5262
5286
|
return query;
|
|
5263
5287
|
}
|
|
5264
|
-
var
|
|
5288
|
+
var logger10 = core.createLogger("agentforge:tools:data:relational:batch");
|
|
5265
5289
|
var DEFAULT_BATCH_SIZE = 100;
|
|
5266
5290
|
var MAX_BATCH_SIZE = 5e3;
|
|
5267
5291
|
var MAX_RETRY_ATTEMPTS = 5;
|
|
@@ -5312,7 +5336,7 @@ async function executeBatchedTask(task, options = {}) {
|
|
|
5312
5336
|
let successfulItems = 0;
|
|
5313
5337
|
let failedItems = 0;
|
|
5314
5338
|
let retries = 0;
|
|
5315
|
-
|
|
5339
|
+
logger10.debug("Starting batched execution", {
|
|
5316
5340
|
operation: task.operation,
|
|
5317
5341
|
totalItems: task.items.length,
|
|
5318
5342
|
totalBatches: batches.length,
|
|
@@ -5351,7 +5375,7 @@ async function executeBatchedTask(task, options = {}) {
|
|
|
5351
5375
|
lastError = error;
|
|
5352
5376
|
if (attempts <= resolved.maxRetries) {
|
|
5353
5377
|
retries += 1;
|
|
5354
|
-
|
|
5378
|
+
logger10.warn("Batch execution failed, retrying", {
|
|
5355
5379
|
operation: task.operation,
|
|
5356
5380
|
batchIndex,
|
|
5357
5381
|
attempts,
|
|
@@ -5390,7 +5414,7 @@ async function executeBatchedTask(task, options = {}) {
|
|
|
5390
5414
|
{ cause: lastError }
|
|
5391
5415
|
);
|
|
5392
5416
|
}
|
|
5393
|
-
|
|
5417
|
+
logger10.warn("Batch execution failed and was recorded for partial success", {
|
|
5394
5418
|
operation: task.operation,
|
|
5395
5419
|
batchIndex,
|
|
5396
5420
|
attempts,
|
|
@@ -5402,7 +5426,7 @@ async function executeBatchedTask(task, options = {}) {
|
|
|
5402
5426
|
}
|
|
5403
5427
|
const executionTime = Date.now() - startTime;
|
|
5404
5428
|
const partialSuccess = successfulItems > 0 && failedItems > 0;
|
|
5405
|
-
|
|
5429
|
+
logger10.debug("Batched execution completed", {
|
|
5406
5430
|
operation: task.operation,
|
|
5407
5431
|
totalItems: task.items.length,
|
|
5408
5432
|
successfulItems,
|
|
@@ -5446,7 +5470,7 @@ async function benchmarkBatchExecution(params) {
|
|
|
5446
5470
|
const timeSavedMs = Math.max(individualExecutionTime - batchedExecutionTime, 0);
|
|
5447
5471
|
const speedupRatio = batchedExecutionTime > 0 ? individualExecutionTime / batchedExecutionTime : 0;
|
|
5448
5472
|
const speedupPercent = individualExecutionTime > 0 ? timeSavedMs / individualExecutionTime * 100 : 0;
|
|
5449
|
-
|
|
5473
|
+
logger10.debug("Batch benchmark completed", {
|
|
5450
5474
|
itemCount: params.items.length,
|
|
5451
5475
|
batchCount: batches.length,
|
|
5452
5476
|
batchSize,
|
|
@@ -5466,7 +5490,7 @@ async function benchmarkBatchExecution(params) {
|
|
|
5466
5490
|
speedupPercent
|
|
5467
5491
|
};
|
|
5468
5492
|
}
|
|
5469
|
-
var
|
|
5493
|
+
var logger11 = core.createLogger("agentforge:tools:data:relational:stream");
|
|
5470
5494
|
var DEFAULT_CHUNK_SIZE = 100;
|
|
5471
5495
|
var MAX_CHUNK_SIZE = 5e3;
|
|
5472
5496
|
var DEFAULT_SAMPLE_SIZE = 50;
|
|
@@ -5599,7 +5623,7 @@ async function executeStreamingSelect(executor, input, options = {}) {
|
|
|
5599
5623
|
const endHeapUsed = process.memoryUsage().heapUsed;
|
|
5600
5624
|
peakHeapUsed = Math.max(peakHeapUsed, endHeapUsed);
|
|
5601
5625
|
const executionTime = Date.now() - startTime;
|
|
5602
|
-
|
|
5626
|
+
logger11.debug("Streaming SELECT execution completed", {
|
|
5603
5627
|
table: input.table,
|
|
5604
5628
|
vendor: input.vendor,
|
|
5605
5629
|
chunkCount,
|
|
@@ -5623,7 +5647,7 @@ async function executeStreamingSelect(executor, input, options = {}) {
|
|
|
5623
5647
|
};
|
|
5624
5648
|
}
|
|
5625
5649
|
async function benchmarkStreamingSelectMemory(executor, input, options = {}) {
|
|
5626
|
-
|
|
5650
|
+
logger11.warn("Running streaming benchmark will execute the SELECT query twice (regular + streaming).", {
|
|
5627
5651
|
table: input.table,
|
|
5628
5652
|
vendor: input.vendor
|
|
5629
5653
|
});
|
|
@@ -5643,7 +5667,7 @@ async function benchmarkStreamingSelectMemory(executor, input, options = {}) {
|
|
|
5643
5667
|
0
|
|
5644
5668
|
);
|
|
5645
5669
|
const memorySavedPercent = nonStreamingPeakHeapUsed > 0 ? memorySavedBytes / nonStreamingPeakHeapUsed * 100 : 0;
|
|
5646
|
-
|
|
5670
|
+
logger11.debug("Streaming benchmark completed", {
|
|
5647
5671
|
table: input.table,
|
|
5648
5672
|
vendor: input.vendor,
|
|
5649
5673
|
nonStreamingRows: nonStreamingRows.length,
|
|
@@ -5661,7 +5685,7 @@ async function benchmarkStreamingSelectMemory(executor, input, options = {}) {
|
|
|
5661
5685
|
memorySavedPercent
|
|
5662
5686
|
};
|
|
5663
5687
|
}
|
|
5664
|
-
var
|
|
5688
|
+
var logger12 = core.createLogger("agentforge:tools:data:relational:transaction");
|
|
5665
5689
|
var transactionSequence = 0;
|
|
5666
5690
|
var SAVEPOINT_NAME_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
5667
5691
|
function toSqlIsolationLevel(level) {
|
|
@@ -5820,7 +5844,7 @@ var ManagedTransaction = class {
|
|
|
5820
5844
|
await this.executeQuery(drizzleOrm.sql.raw("PRAGMA read_uncommitted = 1"));
|
|
5821
5845
|
this.shouldRestoreSqliteReadUncommitted = true;
|
|
5822
5846
|
} else {
|
|
5823
|
-
|
|
5847
|
+
logger12.debug("Ignoring SQLite isolation level override", {
|
|
5824
5848
|
transactionId: this.id,
|
|
5825
5849
|
isolationLevel: this.options.isolationLevel
|
|
5826
5850
|
});
|
|
@@ -5845,7 +5869,7 @@ var ManagedTransaction = class {
|
|
|
5845
5869
|
const targetValue = this.sqliteReadUncommittedOriginal ?? 0;
|
|
5846
5870
|
await this.executeQuery(drizzleOrm.sql.raw(`PRAGMA read_uncommitted = ${targetValue}`));
|
|
5847
5871
|
} catch (error) {
|
|
5848
|
-
|
|
5872
|
+
logger12.warn("Failed to restore SQLite read_uncommitted pragma", {
|
|
5849
5873
|
transactionId: this.id,
|
|
5850
5874
|
error: error instanceof Error ? error.message : String(error)
|
|
5851
5875
|
});
|
|
@@ -5874,7 +5898,7 @@ async function withTransaction(manager, operation, options) {
|
|
|
5874
5898
|
const resolvedOptions = resolveOptions2(options);
|
|
5875
5899
|
const transactionId = `tx-${++transactionSequence}`;
|
|
5876
5900
|
const vendor = manager.getVendor();
|
|
5877
|
-
|
|
5901
|
+
logger12.debug("Starting transaction", {
|
|
5878
5902
|
transactionId,
|
|
5879
5903
|
vendor,
|
|
5880
5904
|
...resolvedOptions.isolationLevel ? { isolationLevel: resolvedOptions.isolationLevel } : {},
|
|
@@ -5901,7 +5925,7 @@ async function withTransaction(manager, operation, options) {
|
|
|
5901
5925
|
if (transaction.isActive()) {
|
|
5902
5926
|
await transaction.commit();
|
|
5903
5927
|
}
|
|
5904
|
-
|
|
5928
|
+
logger12.debug("Transaction committed", {
|
|
5905
5929
|
transactionId,
|
|
5906
5930
|
vendor,
|
|
5907
5931
|
duration: Date.now() - startTime
|
|
@@ -5912,14 +5936,14 @@ async function withTransaction(manager, operation, options) {
|
|
|
5912
5936
|
try {
|
|
5913
5937
|
await transaction.rollback();
|
|
5914
5938
|
} catch (rollbackError) {
|
|
5915
|
-
|
|
5939
|
+
logger12.error("Transaction rollback failed", {
|
|
5916
5940
|
transactionId,
|
|
5917
5941
|
vendor,
|
|
5918
5942
|
error: rollbackError instanceof Error ? rollbackError.message : String(rollbackError)
|
|
5919
5943
|
});
|
|
5920
5944
|
}
|
|
5921
5945
|
}
|
|
5922
|
-
|
|
5946
|
+
logger12.error("Transaction failed", {
|
|
5923
5947
|
transactionId,
|
|
5924
5948
|
vendor,
|
|
5925
5949
|
duration: Date.now() - startTime,
|
|
@@ -5934,7 +5958,7 @@ async function withTransaction(manager, operation, options) {
|
|
|
5934
5958
|
var VALID_TABLE_FILTER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)?$/;
|
|
5935
5959
|
|
|
5936
5960
|
// src/data/relational/schema/schema-inspector.ts
|
|
5937
|
-
var
|
|
5961
|
+
var logger13 = core.createLogger("agentforge:tools:data:relational:schema-inspector");
|
|
5938
5962
|
var DEFAULT_CACHE_TTL_MS = 6e4;
|
|
5939
5963
|
var schemaCache = /* @__PURE__ */ new Map();
|
|
5940
5964
|
var POSTGRES_TABLES_QUERY = `
|
|
@@ -6224,7 +6248,7 @@ var SchemaInspector = class _SchemaInspector {
|
|
|
6224
6248
|
if (!bypassCache && this.cacheKey) {
|
|
6225
6249
|
const cached = schemaCache.get(this.cacheKey);
|
|
6226
6250
|
if (cached && cached.expiresAt > Date.now()) {
|
|
6227
|
-
|
|
6251
|
+
logger13.debug("Schema cache hit", { vendor: this.vendor });
|
|
6228
6252
|
return filterSchemaTables(cloneSchema(cached.schema), tableFilters);
|
|
6229
6253
|
}
|
|
6230
6254
|
}
|
|
@@ -6491,7 +6515,7 @@ var SchemaInspector = class _SchemaInspector {
|
|
|
6491
6515
|
}
|
|
6492
6516
|
}
|
|
6493
6517
|
};
|
|
6494
|
-
var
|
|
6518
|
+
var logger14 = core.createLogger("agentforge:tools:data:relational:schema-validator");
|
|
6495
6519
|
function validateTableExists(schema, tableName) {
|
|
6496
6520
|
const errors = [];
|
|
6497
6521
|
if (!tableName || typeof tableName !== "string") {
|
|
@@ -6505,7 +6529,7 @@ function validateTableExists(schema, tableName) {
|
|
|
6505
6529
|
`Table "${tableName}" does not exist. Available tables: ${available || "(none)"}`
|
|
6506
6530
|
);
|
|
6507
6531
|
}
|
|
6508
|
-
|
|
6532
|
+
logger14.debug("Table existence validation", { tableName, valid: errors.length === 0 });
|
|
6509
6533
|
return { valid: errors.length === 0, errors };
|
|
6510
6534
|
}
|
|
6511
6535
|
function validateColumnsExist(schema, tableName, columnNames) {
|
|
@@ -6528,7 +6552,7 @@ function validateColumnsExist(schema, tableName, columnNames) {
|
|
|
6528
6552
|
);
|
|
6529
6553
|
}
|
|
6530
6554
|
}
|
|
6531
|
-
|
|
6555
|
+
logger14.debug("Column existence validation", {
|
|
6532
6556
|
tableName,
|
|
6533
6557
|
columnCount: columnNames.length,
|
|
6534
6558
|
valid: errors.length === 0
|
|
@@ -6564,7 +6588,7 @@ function validateColumnTypes(schema, tableName, expectedTypes) {
|
|
|
6564
6588
|
);
|
|
6565
6589
|
}
|
|
6566
6590
|
}
|
|
6567
|
-
|
|
6591
|
+
logger14.debug("Column type validation", {
|
|
6568
6592
|
tableName,
|
|
6569
6593
|
typeChecks: Object.keys(expectedTypes).length,
|
|
6570
6594
|
valid: errors.length === 0
|
|
@@ -6584,7 +6608,7 @@ function findTable(schema, tableName) {
|
|
|
6584
6608
|
function formatTableName(table) {
|
|
6585
6609
|
return table.schema ? `${table.schema}.${table.name}` : table.name;
|
|
6586
6610
|
}
|
|
6587
|
-
var
|
|
6611
|
+
var logger15 = core.createLogger("agentforge:tools:data:relational:type-mapper");
|
|
6588
6612
|
var POSTGRES_TYPE_MAP = {
|
|
6589
6613
|
// Numeric
|
|
6590
6614
|
smallint: "number",
|
|
@@ -6750,7 +6774,7 @@ function mapColumnType(vendor, dbType, nullable = false) {
|
|
|
6750
6774
|
const result = { tsType, nullable, dbType };
|
|
6751
6775
|
if (tsType === "unknown" && normalised !== "json" && normalised !== "jsonb") {
|
|
6752
6776
|
result.notes = `No explicit mapping for "${dbType}"; defaulting to unknown`;
|
|
6753
|
-
|
|
6777
|
+
logger15.debug("Unmapped database type", { vendor, dbType, normalised });
|
|
6754
6778
|
}
|
|
6755
6779
|
if ((normalised === "bigint" || normalised === "int8" || normalised === "bigserial") && (vendor === "postgresql" || vendor === "mysql")) {
|
|
6756
6780
|
result.notes = "Mapped to string to avoid JavaScript number precision loss for 64-bit integers";
|
|
@@ -6765,7 +6789,7 @@ function mapSchemaTypes(vendor, columns) {
|
|
|
6765
6789
|
}
|
|
6766
6790
|
result.get(col.table).set(col.name, mapColumnType(vendor, col.type, col.nullable));
|
|
6767
6791
|
}
|
|
6768
|
-
|
|
6792
|
+
logger15.debug("Schema type mapping complete", {
|
|
6769
6793
|
vendor,
|
|
6770
6794
|
tables: result.size,
|
|
6771
6795
|
columns: columns.length
|
|
@@ -6782,7 +6806,7 @@ function normaliseDbType(raw) {
|
|
|
6782
6806
|
type = type.replace(/\s+unsigned$/, "");
|
|
6783
6807
|
return type.trim();
|
|
6784
6808
|
}
|
|
6785
|
-
var
|
|
6809
|
+
var logger16 = core.createLogger("agentforge:tools:data:relational:schema-diff");
|
|
6786
6810
|
function diffSchemas(before, after) {
|
|
6787
6811
|
const tableDiffs = [];
|
|
6788
6812
|
let columnsAdded = 0;
|
|
@@ -6822,7 +6846,7 @@ function diffSchemas(before, after) {
|
|
|
6822
6846
|
const tablesRemoved = tableDiffs.filter((d) => d.type === "removed").length;
|
|
6823
6847
|
const tablesChanged = tableDiffs.filter((d) => d.type === "changed").length;
|
|
6824
6848
|
const identical = tableDiffs.length === 0;
|
|
6825
|
-
|
|
6849
|
+
logger16.debug("Schema diff computed", {
|
|
6826
6850
|
identical,
|
|
6827
6851
|
tablesAdded,
|
|
6828
6852
|
tablesRemoved,
|
|
@@ -6866,7 +6890,7 @@ function importSchemaFromJson(json) {
|
|
|
6866
6890
|
throw new Error(`Invalid schema JSON: table "${table.name}" missing "primaryKey" array`);
|
|
6867
6891
|
}
|
|
6868
6892
|
}
|
|
6869
|
-
|
|
6893
|
+
logger16.debug("Schema imported from JSON", {
|
|
6870
6894
|
vendor: obj.vendor,
|
|
6871
6895
|
tableCount: obj.tables.length
|
|
6872
6896
|
});
|
|
@@ -7163,7 +7187,7 @@ function isSafeValidationError(error) {
|
|
|
7163
7187
|
}
|
|
7164
7188
|
|
|
7165
7189
|
// src/data/relational/tools/relational-select/executor.ts
|
|
7166
|
-
var
|
|
7190
|
+
var logger17 = core.createLogger("agentforge:tools:data:relational:select");
|
|
7167
7191
|
function toSelectQueryInput(input) {
|
|
7168
7192
|
return {
|
|
7169
7193
|
table: input.table,
|
|
@@ -7177,7 +7201,7 @@ function toSelectQueryInput(input) {
|
|
|
7177
7201
|
}
|
|
7178
7202
|
async function executeSelect(manager, input, context) {
|
|
7179
7203
|
const startTime = Date.now();
|
|
7180
|
-
|
|
7204
|
+
logger17.debug("Building SELECT query", {
|
|
7181
7205
|
vendor: input.vendor,
|
|
7182
7206
|
table: input.table,
|
|
7183
7207
|
hasWhere: !!input.where,
|
|
@@ -7195,7 +7219,7 @@ async function executeSelect(manager, input, context) {
|
|
|
7195
7219
|
};
|
|
7196
7220
|
const streamInput = toSelectQueryInput(input);
|
|
7197
7221
|
if (input.streaming.benchmark) {
|
|
7198
|
-
|
|
7222
|
+
logger17.warn("Streaming benchmark enabled; SELECT will execute up to three times (result + benchmark regular + benchmark streaming).", {
|
|
7199
7223
|
vendor: input.vendor,
|
|
7200
7224
|
table: input.table,
|
|
7201
7225
|
chunkSize: streamOptions.chunkSize ?? DEFAULT_CHUNK_SIZE,
|
|
@@ -7206,7 +7230,7 @@ async function executeSelect(manager, input, context) {
|
|
|
7206
7230
|
const streamResult = await executeStreamingSelect(executor, streamInput, streamOptions);
|
|
7207
7231
|
const benchmark = input.streaming.benchmark ? await benchmarkStreamingSelectMemory(executor, streamInput, streamOptions) : void 0;
|
|
7208
7232
|
const executionTime2 = Date.now() - startTime;
|
|
7209
|
-
|
|
7233
|
+
logger17.debug("Streaming SELECT query executed successfully", {
|
|
7210
7234
|
vendor: input.vendor,
|
|
7211
7235
|
table: input.table,
|
|
7212
7236
|
rowCount: streamResult.rowCount,
|
|
@@ -7235,7 +7259,7 @@ async function executeSelect(manager, input, context) {
|
|
|
7235
7259
|
const executionTime = Date.now() - startTime;
|
|
7236
7260
|
const rows = Array.isArray(result) ? result : result.rows || [];
|
|
7237
7261
|
const rowCount = rows.length;
|
|
7238
|
-
|
|
7262
|
+
logger17.debug("SELECT query executed successfully", {
|
|
7239
7263
|
vendor: input.vendor,
|
|
7240
7264
|
table: input.table,
|
|
7241
7265
|
rowCount,
|
|
@@ -7248,7 +7272,7 @@ async function executeSelect(manager, input, context) {
|
|
|
7248
7272
|
};
|
|
7249
7273
|
} catch (error) {
|
|
7250
7274
|
const executionTime = Date.now() - startTime;
|
|
7251
|
-
|
|
7275
|
+
logger17.error("SELECT query execution failed", {
|
|
7252
7276
|
vendor: input.vendor,
|
|
7253
7277
|
table: input.table,
|
|
7254
7278
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -7424,7 +7448,7 @@ function isSafeInsertError(error) {
|
|
|
7424
7448
|
}
|
|
7425
7449
|
|
|
7426
7450
|
// src/data/relational/tools/relational-insert/executor.ts
|
|
7427
|
-
var
|
|
7451
|
+
var logger18 = core.createLogger("agentforge:tools:data:relational:insert");
|
|
7428
7452
|
function toNumber(value) {
|
|
7429
7453
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
7430
7454
|
}
|
|
@@ -7573,7 +7597,7 @@ async function executeInsertInBatchMode(manager, input, context, options) {
|
|
|
7573
7597
|
maxRetries: options.maxRetries,
|
|
7574
7598
|
retryDelayMs: options.retryDelayMs,
|
|
7575
7599
|
onProgress: (progress) => {
|
|
7576
|
-
|
|
7600
|
+
logger18.debug("INSERT batch progress", {
|
|
7577
7601
|
vendor: input.vendor,
|
|
7578
7602
|
table: input.table,
|
|
7579
7603
|
...progress
|
|
@@ -7586,7 +7610,7 @@ async function executeInsertInBatchMode(manager, input, context, options) {
|
|
|
7586
7610
|
const insertedIds = batchResult.results.flatMap((result) => result.insertedIds);
|
|
7587
7611
|
let benchmark;
|
|
7588
7612
|
if (options.benchmark) {
|
|
7589
|
-
|
|
7613
|
+
logger18.warn("INSERT batch benchmark enabled. Synthetic benchmark callbacks are side-effect free and do not execute SQL.", {
|
|
7590
7614
|
vendor: input.vendor,
|
|
7591
7615
|
table: input.table,
|
|
7592
7616
|
totalRows: input.data.length,
|
|
@@ -7623,7 +7647,7 @@ async function executeInsertInBatchMode(manager, input, context, options) {
|
|
|
7623
7647
|
}
|
|
7624
7648
|
async function executeInsert(manager, input, context) {
|
|
7625
7649
|
const startTime = Date.now();
|
|
7626
|
-
|
|
7650
|
+
logger18.debug("Building INSERT query", {
|
|
7627
7651
|
vendor: input.vendor,
|
|
7628
7652
|
table: input.table,
|
|
7629
7653
|
isBatch: Array.isArray(input.data),
|
|
@@ -7639,7 +7663,7 @@ async function executeInsert(manager, input, context) {
|
|
|
7639
7663
|
batchOptions
|
|
7640
7664
|
) : await executeInsertOnce(manager, input, context);
|
|
7641
7665
|
const executionTime = Date.now() - startTime;
|
|
7642
|
-
|
|
7666
|
+
logger18.debug("INSERT query executed successfully", {
|
|
7643
7667
|
vendor: input.vendor,
|
|
7644
7668
|
table: input.table,
|
|
7645
7669
|
rowCount: result.rowCount,
|
|
@@ -7655,7 +7679,7 @@ async function executeInsert(manager, input, context) {
|
|
|
7655
7679
|
};
|
|
7656
7680
|
} catch (error) {
|
|
7657
7681
|
const executionTime = Date.now() - startTime;
|
|
7658
|
-
|
|
7682
|
+
logger18.error("INSERT query execution failed", {
|
|
7659
7683
|
vendor: input.vendor,
|
|
7660
7684
|
table: input.table,
|
|
7661
7685
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -7985,7 +8009,7 @@ function isSafeUpdateError(error) {
|
|
|
7985
8009
|
}
|
|
7986
8010
|
|
|
7987
8011
|
// src/data/relational/tools/relational-update/executor.ts
|
|
7988
|
-
var
|
|
8012
|
+
var logger19 = core.createLogger("agentforge:tools:data:relational:update");
|
|
7989
8013
|
function toNumber2(value) {
|
|
7990
8014
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
7991
8015
|
}
|
|
@@ -8107,7 +8131,7 @@ async function executeUpdateInBatchMode(manager, input, context, options) {
|
|
|
8107
8131
|
maxRetries: options.maxRetries,
|
|
8108
8132
|
retryDelayMs: options.retryDelayMs,
|
|
8109
8133
|
onProgress: (progress) => {
|
|
8110
|
-
|
|
8134
|
+
logger19.debug("UPDATE batch progress", {
|
|
8111
8135
|
vendor: input.vendor,
|
|
8112
8136
|
table: input.table,
|
|
8113
8137
|
...progress
|
|
@@ -8119,7 +8143,7 @@ async function executeUpdateInBatchMode(manager, input, context, options) {
|
|
|
8119
8143
|
const operationFailures = batchResult.results.flatMap((result) => result.failures);
|
|
8120
8144
|
let benchmark;
|
|
8121
8145
|
if (options.benchmark) {
|
|
8122
|
-
|
|
8146
|
+
logger19.warn("UPDATE batch benchmark enabled. Synthetic benchmark callbacks are side-effect free and do not execute SQL.", {
|
|
8123
8147
|
vendor: input.vendor,
|
|
8124
8148
|
table: input.table,
|
|
8125
8149
|
operationCount: input.operations.length,
|
|
@@ -8154,7 +8178,7 @@ async function executeUpdateInBatchMode(manager, input, context, options) {
|
|
|
8154
8178
|
}
|
|
8155
8179
|
async function executeUpdate(manager, input, context) {
|
|
8156
8180
|
const startTime = Date.now();
|
|
8157
|
-
|
|
8181
|
+
logger19.debug("Building UPDATE query", {
|
|
8158
8182
|
vendor: input.vendor,
|
|
8159
8183
|
table: input.table,
|
|
8160
8184
|
hasWhere: !!input.where?.length,
|
|
@@ -8172,7 +8196,7 @@ async function executeUpdate(manager, input, context) {
|
|
|
8172
8196
|
batchOptions
|
|
8173
8197
|
) : await executeSingleUpdate(manager, input, toSingleUpdateOperation(input), context);
|
|
8174
8198
|
const executionTime = Date.now() - startTime;
|
|
8175
|
-
|
|
8199
|
+
logger19.debug("UPDATE query executed successfully", {
|
|
8176
8200
|
vendor: input.vendor,
|
|
8177
8201
|
table: input.table,
|
|
8178
8202
|
rowCount: result.rowCount,
|
|
@@ -8186,7 +8210,7 @@ async function executeUpdate(manager, input, context) {
|
|
|
8186
8210
|
};
|
|
8187
8211
|
} catch (error) {
|
|
8188
8212
|
const executionTime = Date.now() - startTime;
|
|
8189
|
-
|
|
8213
|
+
logger19.error("UPDATE query execution failed", {
|
|
8190
8214
|
vendor: input.vendor,
|
|
8191
8215
|
table: input.table,
|
|
8192
8216
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -8490,7 +8514,7 @@ function isSafeDeleteError(error) {
|
|
|
8490
8514
|
}
|
|
8491
8515
|
|
|
8492
8516
|
// src/data/relational/tools/relational-delete/executor.ts
|
|
8493
|
-
var
|
|
8517
|
+
var logger20 = core.createLogger("agentforge:tools:data:relational:delete");
|
|
8494
8518
|
function toNumber3(value) {
|
|
8495
8519
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8496
8520
|
}
|
|
@@ -8611,7 +8635,7 @@ async function executeDeleteInBatchMode(manager, input, context, options) {
|
|
|
8611
8635
|
maxRetries: options.maxRetries,
|
|
8612
8636
|
retryDelayMs: options.retryDelayMs,
|
|
8613
8637
|
onProgress: (progress) => {
|
|
8614
|
-
|
|
8638
|
+
logger20.debug("DELETE batch progress", {
|
|
8615
8639
|
vendor: input.vendor,
|
|
8616
8640
|
table: input.table,
|
|
8617
8641
|
...progress
|
|
@@ -8624,7 +8648,7 @@ async function executeDeleteInBatchMode(manager, input, context, options) {
|
|
|
8624
8648
|
const operationFailures = batchResult.results.flatMap((result) => result.failures);
|
|
8625
8649
|
let benchmark;
|
|
8626
8650
|
if (options.benchmark) {
|
|
8627
|
-
|
|
8651
|
+
logger20.warn("DELETE batch benchmark enabled. Synthetic benchmark callbacks are side-effect free and do not execute SQL.", {
|
|
8628
8652
|
vendor: input.vendor,
|
|
8629
8653
|
table: input.table,
|
|
8630
8654
|
operationCount: input.operations.length,
|
|
@@ -8660,7 +8684,7 @@ async function executeDeleteInBatchMode(manager, input, context, options) {
|
|
|
8660
8684
|
}
|
|
8661
8685
|
async function executeDelete(manager, input, context) {
|
|
8662
8686
|
const startTime = Date.now();
|
|
8663
|
-
|
|
8687
|
+
logger20.debug("Building DELETE query", {
|
|
8664
8688
|
vendor: input.vendor,
|
|
8665
8689
|
table: input.table,
|
|
8666
8690
|
hasWhere: !!input.where?.length,
|
|
@@ -8679,7 +8703,7 @@ async function executeDelete(manager, input, context) {
|
|
|
8679
8703
|
batchOptions
|
|
8680
8704
|
) : await executeSingleDelete(manager, input, toSingleDeleteOperation(input), context);
|
|
8681
8705
|
const executionTime = Date.now() - startTime;
|
|
8682
|
-
|
|
8706
|
+
logger20.debug("DELETE query executed successfully", {
|
|
8683
8707
|
vendor: input.vendor,
|
|
8684
8708
|
table: input.table,
|
|
8685
8709
|
rowCount: result.rowCount,
|
|
@@ -8695,7 +8719,7 @@ async function executeDelete(manager, input, context) {
|
|
|
8695
8719
|
};
|
|
8696
8720
|
} catch (error) {
|
|
8697
8721
|
const executionTime = Date.now() - startTime;
|
|
8698
|
-
|
|
8722
|
+
logger20.error("DELETE query execution failed", {
|
|
8699
8723
|
vendor: input.vendor,
|
|
8700
8724
|
table: input.table,
|
|
8701
8725
|
error: error instanceof Error ? error.message : String(error),
|
|
@@ -8800,7 +8824,7 @@ function isSafeGetSchemaValidationError(error) {
|
|
|
8800
8824
|
}
|
|
8801
8825
|
|
|
8802
8826
|
// src/data/relational/tools/relational-get-schema.ts
|
|
8803
|
-
var
|
|
8827
|
+
var logger21 = core.createLogger("agentforge:tools:data:relational:get-schema");
|
|
8804
8828
|
function buildSchemaCacheKey(vendor, connectionString, database) {
|
|
8805
8829
|
const databaseScope = database ?? "default";
|
|
8806
8830
|
const connectionHash = crypto.createHash("sha256").update(connectionString).digest("hex");
|
|
@@ -8872,7 +8896,7 @@ var relationalGetSchema = core.toolBuilder().name("relational-get-schema").displ
|
|
|
8872
8896
|
summary
|
|
8873
8897
|
};
|
|
8874
8898
|
} catch (error) {
|
|
8875
|
-
|
|
8899
|
+
logger21.error("Schema introspection failed", {
|
|
8876
8900
|
vendor: input.vendor,
|
|
8877
8901
|
hasTablesFilter: Array.isArray(input.tables),
|
|
8878
8902
|
tablesFilterCount: input.tables?.length ?? 0,
|
|
@@ -10038,7 +10062,7 @@ var AskHumanInputSchema = zod.z.object({
|
|
|
10038
10062
|
suggestions: zod.z.array(zod.z.string()).optional().describe("Suggested responses for the human")
|
|
10039
10063
|
});
|
|
10040
10064
|
var logLevel3 = process.env.LOG_LEVEL?.toLowerCase() || core.LogLevel.INFO;
|
|
10041
|
-
var
|
|
10065
|
+
var logger22 = core.createLogger("agentforge:tools:agent:ask-human", { level: logLevel3 });
|
|
10042
10066
|
function isRecord(value) {
|
|
10043
10067
|
return typeof value === "object" && value !== null;
|
|
10044
10068
|
}
|
|
@@ -10103,7 +10127,7 @@ function createAskHumanTool() {
|
|
|
10103
10127
|
suggestions: validatedInput.suggestions,
|
|
10104
10128
|
status: "pending"
|
|
10105
10129
|
};
|
|
10106
|
-
|
|
10130
|
+
logger22.debug("About to call interrupt()", {
|
|
10107
10131
|
humanRequest: {
|
|
10108
10132
|
id: humanRequest.id,
|
|
10109
10133
|
question: humanRequest.question,
|
|
@@ -10119,13 +10143,13 @@ function createAskHumanTool() {
|
|
|
10119
10143
|
let response;
|
|
10120
10144
|
try {
|
|
10121
10145
|
response = interrupt(humanRequest);
|
|
10122
|
-
|
|
10146
|
+
logger22.debug("interrupt() returned successfully", {
|
|
10123
10147
|
responseType: typeof response,
|
|
10124
10148
|
hasResponse: response != null,
|
|
10125
10149
|
...typeof response === "string" ? { responseLength: response.length } : {}
|
|
10126
10150
|
});
|
|
10127
10151
|
} catch (error) {
|
|
10128
|
-
|
|
10152
|
+
logger22.debug("interrupt() threw error (expected for GraphInterrupt)", {
|
|
10129
10153
|
...error && typeof error === "object" && "constructor" in error ? { errorType: error.constructor?.name } : {},
|
|
10130
10154
|
error: error instanceof Error ? error.message : String(error)
|
|
10131
10155
|
});
|