@probelabs/probe 0.6.0-rc116 → 0.6.0-rc117
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/build/agent/ProbeAgent.js +100 -10
- package/build/agent/index.js +342 -217
- package/build/agent/probeTool.js +93 -18
- package/build/agent/schemaUtils.js +1 -1
- package/build/index.js +4 -0
- package/cjs/agent/ProbeAgent.cjs +343 -218
- package/cjs/index.cjs +142 -13
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +100 -10
- package/src/agent/probeTool.js +93 -18
- package/src/agent/schemaUtils.js +1 -1
- package/src/index.js +4 -0
package/cjs/index.cjs
CHANGED
|
@@ -30339,14 +30339,53 @@ var init_probeTool = __esm({
|
|
|
30339
30339
|
if (!targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
|
|
30340
30340
|
throw new Error("Path traversal attempt detected. Access denied.");
|
|
30341
30341
|
}
|
|
30342
|
+
const debug = process.env.DEBUG === "1";
|
|
30343
|
+
if (debug) {
|
|
30344
|
+
console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
|
|
30345
|
+
}
|
|
30342
30346
|
try {
|
|
30343
|
-
const files = await
|
|
30344
|
-
|
|
30345
|
-
|
|
30346
|
-
|
|
30347
|
-
|
|
30347
|
+
const files = await import_fs4.promises.readdir(targetDir, { withFileTypes: true });
|
|
30348
|
+
const formatSize = (size) => {
|
|
30349
|
+
if (size < 1024) return `${size}B`;
|
|
30350
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
|
|
30351
|
+
if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(1)}M`;
|
|
30352
|
+
return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
|
|
30353
|
+
};
|
|
30354
|
+
const entries = await Promise.all(files.map(async (file) => {
|
|
30355
|
+
const isDirectory = file.isDirectory();
|
|
30356
|
+
const fullPath = import_path7.default.join(targetDir, file.name);
|
|
30357
|
+
let size = 0;
|
|
30358
|
+
try {
|
|
30359
|
+
const stats = await import_fs4.promises.stat(fullPath);
|
|
30360
|
+
size = stats.size;
|
|
30361
|
+
} catch (statError) {
|
|
30362
|
+
if (debug) {
|
|
30363
|
+
console.log(`[DEBUG] Could not stat file ${file.name}:`, statError.message);
|
|
30364
|
+
}
|
|
30365
|
+
}
|
|
30366
|
+
return {
|
|
30367
|
+
name: file.name,
|
|
30368
|
+
isDirectory,
|
|
30369
|
+
size
|
|
30370
|
+
};
|
|
30371
|
+
}));
|
|
30372
|
+
entries.sort((a3, b3) => {
|
|
30373
|
+
if (a3.isDirectory && !b3.isDirectory) return -1;
|
|
30374
|
+
if (!a3.isDirectory && b3.isDirectory) return 1;
|
|
30375
|
+
return a3.name.localeCompare(b3.name);
|
|
30348
30376
|
});
|
|
30349
|
-
|
|
30377
|
+
const formatted = entries.map((entry) => {
|
|
30378
|
+
const type = entry.isDirectory ? "dir " : "file";
|
|
30379
|
+
const sizeStr = formatSize(entry.size).padStart(8);
|
|
30380
|
+
return `${type} ${sizeStr} ${entry.name}`;
|
|
30381
|
+
});
|
|
30382
|
+
if (debug) {
|
|
30383
|
+
console.log(`[DEBUG] Found ${entries.length} files/directories in ${targetDir}`);
|
|
30384
|
+
}
|
|
30385
|
+
const header = `${targetDir}:
|
|
30386
|
+
`;
|
|
30387
|
+
const output = header + formatted.join("\n");
|
|
30388
|
+
return output;
|
|
30350
30389
|
} catch (error2) {
|
|
30351
30390
|
throw new Error(`Failed to list files: ${error2.message}`);
|
|
30352
30391
|
}
|
|
@@ -30364,6 +30403,9 @@ var init_probeTool = __esm({
|
|
|
30364
30403
|
if (!targetDir.startsWith(secureBaseDir + import_path7.default.sep) && targetDir !== secureBaseDir) {
|
|
30365
30404
|
throw new Error("Path traversal attempt detected. Access denied.");
|
|
30366
30405
|
}
|
|
30406
|
+
if (pattern.includes("**/**") || pattern.split("*").length > 10) {
|
|
30407
|
+
throw new Error("Pattern too complex. Please use a simpler glob pattern.");
|
|
30408
|
+
}
|
|
30367
30409
|
try {
|
|
30368
30410
|
const options = {
|
|
30369
30411
|
cwd: targetDir,
|
|
@@ -30373,7 +30415,17 @@ var init_probeTool = __esm({
|
|
|
30373
30415
|
if (!recursive) {
|
|
30374
30416
|
options.deep = 1;
|
|
30375
30417
|
}
|
|
30376
|
-
const
|
|
30418
|
+
const timeoutPromise = new Promise((_2, reject2) => {
|
|
30419
|
+
setTimeout(() => reject2(new Error("Search operation timed out after 10 seconds")), 1e4);
|
|
30420
|
+
});
|
|
30421
|
+
const files = await Promise.race([
|
|
30422
|
+
(0, import_glob.glob)(pattern, options),
|
|
30423
|
+
timeoutPromise
|
|
30424
|
+
]);
|
|
30425
|
+
const maxResults = 1e3;
|
|
30426
|
+
if (files.length > maxResults) {
|
|
30427
|
+
return files.slice(0, maxResults);
|
|
30428
|
+
}
|
|
30377
30429
|
return files;
|
|
30378
30430
|
} catch (error2) {
|
|
30379
30431
|
throw new Error(`Failed to search files: ${error2.message}`);
|
|
@@ -57777,8 +57829,8 @@ When presented with a broken Mermaid diagram, analyze it thoroughly and provide
|
|
|
57777
57829
|
debug: this.options.debug,
|
|
57778
57830
|
tracer: this.options.tracer,
|
|
57779
57831
|
allowEdit: this.options.allowEdit,
|
|
57780
|
-
maxIterations:
|
|
57781
|
-
//
|
|
57832
|
+
maxIterations: 10,
|
|
57833
|
+
// Allow more iterations for mermaid fixing to handle complex diagrams
|
|
57782
57834
|
disableMermaidValidation: true
|
|
57783
57835
|
// CRITICAL: Disable mermaid validation in nested agent to prevent infinite recursion
|
|
57784
57836
|
});
|
|
@@ -58678,6 +58730,18 @@ var init_ProbeAgent = __esm({
|
|
|
58678
58730
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
58679
58731
|
}
|
|
58680
58732
|
this.wrappedTools = wrappedTools;
|
|
58733
|
+
if (this.debug) {
|
|
58734
|
+
console.error("\n[DEBUG] ========================================");
|
|
58735
|
+
console.error("[DEBUG] ProbeAgent Tools Initialized");
|
|
58736
|
+
console.error("[DEBUG] Session ID:", this.sessionId);
|
|
58737
|
+
console.error("[DEBUG] Available tools:");
|
|
58738
|
+
for (const toolName of Object.keys(this.toolImplementations)) {
|
|
58739
|
+
console.error(`[DEBUG] - ${toolName}`);
|
|
58740
|
+
}
|
|
58741
|
+
console.error("[DEBUG] Allowed folders:", this.allowedFolders);
|
|
58742
|
+
console.error("[DEBUG] Outline mode:", this.outline);
|
|
58743
|
+
console.error("[DEBUG] ========================================\n");
|
|
58744
|
+
}
|
|
58681
58745
|
}
|
|
58682
58746
|
/**
|
|
58683
58747
|
* Initialize the AI model based on available API keys and forced provider setting
|
|
@@ -59448,12 +59512,28 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
59448
59512
|
const { type } = parsedTool;
|
|
59449
59513
|
if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
59450
59514
|
try {
|
|
59451
|
-
if (this.debug)
|
|
59515
|
+
if (this.debug) {
|
|
59516
|
+
console.error(`
|
|
59517
|
+
[DEBUG] ========================================`);
|
|
59518
|
+
console.error(`[DEBUG] Executing MCP tool: ${toolName}`);
|
|
59519
|
+
console.error(`[DEBUG] Arguments:`);
|
|
59520
|
+
for (const [key, value] of Object.entries(params)) {
|
|
59521
|
+
const displayValue = typeof value === "string" && value.length > 100 ? value.substring(0, 100) + "..." : value;
|
|
59522
|
+
console.error(`[DEBUG] ${key}: ${JSON.stringify(displayValue)}`);
|
|
59523
|
+
}
|
|
59524
|
+
console.error(`[DEBUG] ========================================
|
|
59525
|
+
`);
|
|
59526
|
+
}
|
|
59452
59527
|
const executionResult = await this.mcpBridge.mcpTools[toolName].execute(params);
|
|
59453
59528
|
const toolResultContent = typeof executionResult === "string" ? executionResult : JSON.stringify(executionResult, null, 2);
|
|
59454
|
-
const preview = createMessagePreview(toolResultContent);
|
|
59455
59529
|
if (this.debug) {
|
|
59456
|
-
|
|
59530
|
+
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
|
|
59531
|
+
console.error(`[DEBUG] ========================================`);
|
|
59532
|
+
console.error(`[DEBUG] MCP tool '${toolName}' completed successfully`);
|
|
59533
|
+
console.error(`[DEBUG] Result preview:`);
|
|
59534
|
+
console.error(preview);
|
|
59535
|
+
console.error(`[DEBUG] ========================================
|
|
59536
|
+
`);
|
|
59457
59537
|
}
|
|
59458
59538
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
59459
59539
|
${toolResultContent}
|
|
@@ -59461,7 +59541,13 @@ ${toolResultContent}
|
|
|
59461
59541
|
} catch (error2) {
|
|
59462
59542
|
console.error(`Error executing MCP tool ${toolName}:`, error2);
|
|
59463
59543
|
const toolResultContent = `Error executing MCP tool ${toolName}: ${error2.message}`;
|
|
59464
|
-
if (this.debug)
|
|
59544
|
+
if (this.debug) {
|
|
59545
|
+
console.error(`[DEBUG] ========================================`);
|
|
59546
|
+
console.error(`[DEBUG] MCP tool '${toolName}' failed with error:`);
|
|
59547
|
+
console.error(`[DEBUG] ${error2.message}`);
|
|
59548
|
+
console.error(`[DEBUG] ========================================
|
|
59549
|
+
`);
|
|
59550
|
+
}
|
|
59465
59551
|
currentMessages.push({ role: "user", content: `<tool_result>
|
|
59466
59552
|
${toolResultContent}
|
|
59467
59553
|
</tool_result>` });
|
|
@@ -59473,6 +59559,18 @@ ${toolResultContent}
|
|
|
59473
59559
|
sessionId: this.sessionId,
|
|
59474
59560
|
workingDirectory: this.allowedFolders && this.allowedFolders[0] || process.cwd()
|
|
59475
59561
|
};
|
|
59562
|
+
if (this.debug) {
|
|
59563
|
+
console.error(`
|
|
59564
|
+
[DEBUG] ========================================`);
|
|
59565
|
+
console.error(`[DEBUG] Executing tool: ${toolName}`);
|
|
59566
|
+
console.error(`[DEBUG] Arguments:`);
|
|
59567
|
+
for (const [key, value] of Object.entries(params)) {
|
|
59568
|
+
const displayValue = typeof value === "string" && value.length > 100 ? value.substring(0, 100) + "..." : value;
|
|
59569
|
+
console.error(`[DEBUG] ${key}: ${JSON.stringify(displayValue)}`);
|
|
59570
|
+
}
|
|
59571
|
+
console.error(`[DEBUG] ========================================
|
|
59572
|
+
`);
|
|
59573
|
+
}
|
|
59476
59574
|
this.events.emit("toolCall", {
|
|
59477
59575
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
59478
59576
|
name: toolName,
|
|
@@ -59514,6 +59612,15 @@ ${toolResultContent}
|
|
|
59514
59612
|
} else {
|
|
59515
59613
|
toolResult = await executeToolCall();
|
|
59516
59614
|
}
|
|
59615
|
+
if (this.debug) {
|
|
59616
|
+
const resultPreview = typeof toolResult === "string" ? toolResult.length > 500 ? toolResult.substring(0, 500) + "..." : toolResult : toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + "..." : "No Result";
|
|
59617
|
+
console.error(`[DEBUG] ========================================`);
|
|
59618
|
+
console.error(`[DEBUG] Tool '${toolName}' completed successfully`);
|
|
59619
|
+
console.error(`[DEBUG] Result preview:`);
|
|
59620
|
+
console.error(resultPreview);
|
|
59621
|
+
console.error(`[DEBUG] ========================================
|
|
59622
|
+
`);
|
|
59623
|
+
}
|
|
59517
59624
|
this.events.emit("toolCall", {
|
|
59518
59625
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
59519
59626
|
name: toolName,
|
|
@@ -59522,6 +59629,13 @@ ${toolResultContent}
|
|
|
59522
59629
|
status: "completed"
|
|
59523
59630
|
});
|
|
59524
59631
|
} catch (toolError) {
|
|
59632
|
+
if (this.debug) {
|
|
59633
|
+
console.error(`[DEBUG] ========================================`);
|
|
59634
|
+
console.error(`[DEBUG] Tool '${toolName}' failed with error:`);
|
|
59635
|
+
console.error(`[DEBUG] ${toolError.message}`);
|
|
59636
|
+
console.error(`[DEBUG] ========================================
|
|
59637
|
+
`);
|
|
59638
|
+
}
|
|
59525
59639
|
this.events.emit("toolCall", {
|
|
59526
59640
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
59527
59641
|
name: toolName,
|
|
@@ -59571,6 +59685,16 @@ Error: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(",
|
|
|
59571
59685
|
}
|
|
59572
59686
|
}
|
|
59573
59687
|
} else {
|
|
59688
|
+
const hasMermaidCodeBlock = /```mermaid\s*\n[\s\S]*?\n```/.test(assistantResponseContent);
|
|
59689
|
+
const hasNoSchemaOrTools = !options.schema && validTools.length === 0;
|
|
59690
|
+
if (hasMermaidCodeBlock && hasNoSchemaOrTools) {
|
|
59691
|
+
finalResult = assistantResponseContent;
|
|
59692
|
+
completionAttempted = true;
|
|
59693
|
+
if (this.debug) {
|
|
59694
|
+
console.error(`[DEBUG] Accepting mermaid code block as valid completion (no schema, no tools)`);
|
|
59695
|
+
}
|
|
59696
|
+
break;
|
|
59697
|
+
}
|
|
59574
59698
|
currentMessages.push({ role: "assistant", content: assistantResponseContent });
|
|
59575
59699
|
let reminderContent;
|
|
59576
59700
|
if (options.schema) {
|
|
@@ -60284,12 +60408,14 @@ __export(index_exports, {
|
|
|
60284
60408
|
getBinaryPath: () => getBinaryPath,
|
|
60285
60409
|
initializeSimpleTelemetryFromOptions: () => initializeSimpleTelemetryFromOptions,
|
|
60286
60410
|
listFilesByLevel: () => listFilesByLevel,
|
|
60411
|
+
listFilesToolInstance: () => listFilesToolInstance,
|
|
60287
60412
|
parseXmlToolCall: () => parseXmlToolCall,
|
|
60288
60413
|
query: () => query,
|
|
60289
60414
|
querySchema: () => querySchema,
|
|
60290
60415
|
queryTool: () => queryTool,
|
|
60291
60416
|
queryToolDefinition: () => queryToolDefinition,
|
|
60292
60417
|
search: () => search,
|
|
60418
|
+
searchFilesToolInstance: () => searchFilesToolInstance,
|
|
60293
60419
|
searchSchema: () => searchSchema,
|
|
60294
60420
|
searchTool: () => searchTool,
|
|
60295
60421
|
searchToolDefinition: () => searchToolDefinition,
|
|
@@ -60312,6 +60438,7 @@ var init_index = __esm({
|
|
|
60312
60438
|
init_bash();
|
|
60313
60439
|
init_ProbeAgent();
|
|
60314
60440
|
init_simpleTelemetry();
|
|
60441
|
+
init_probeTool();
|
|
60315
60442
|
}
|
|
60316
60443
|
});
|
|
60317
60444
|
init_index();
|
|
@@ -60337,12 +60464,14 @@ init_index();
|
|
|
60337
60464
|
getBinaryPath,
|
|
60338
60465
|
initializeSimpleTelemetryFromOptions,
|
|
60339
60466
|
listFilesByLevel,
|
|
60467
|
+
listFilesToolInstance,
|
|
60340
60468
|
parseXmlToolCall,
|
|
60341
60469
|
query,
|
|
60342
60470
|
querySchema,
|
|
60343
60471
|
queryTool,
|
|
60344
60472
|
queryToolDefinition,
|
|
60345
60473
|
search,
|
|
60474
|
+
searchFilesToolInstance,
|
|
60346
60475
|
searchSchema,
|
|
60347
60476
|
searchTool,
|
|
60348
60477
|
searchToolDefinition,
|
package/package.json
CHANGED
package/src/agent/ProbeAgent.js
CHANGED
|
@@ -188,9 +188,23 @@ export class ProbeAgent {
|
|
|
188
188
|
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
189
189
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
190
190
|
}
|
|
191
|
-
|
|
191
|
+
|
|
192
192
|
// Store wrapped tools for ACP system
|
|
193
193
|
this.wrappedTools = wrappedTools;
|
|
194
|
+
|
|
195
|
+
// Log available tools in debug mode
|
|
196
|
+
if (this.debug) {
|
|
197
|
+
console.error('\n[DEBUG] ========================================');
|
|
198
|
+
console.error('[DEBUG] ProbeAgent Tools Initialized');
|
|
199
|
+
console.error('[DEBUG] Session ID:', this.sessionId);
|
|
200
|
+
console.error('[DEBUG] Available tools:');
|
|
201
|
+
for (const toolName of Object.keys(this.toolImplementations)) {
|
|
202
|
+
console.error(`[DEBUG] - ${toolName}`);
|
|
203
|
+
}
|
|
204
|
+
console.error('[DEBUG] Allowed folders:', this.allowedFolders);
|
|
205
|
+
console.error('[DEBUG] Outline mode:', this.outline);
|
|
206
|
+
console.error('[DEBUG] ========================================\n');
|
|
207
|
+
}
|
|
194
208
|
}
|
|
195
209
|
|
|
196
210
|
/**
|
|
@@ -1117,34 +1131,74 @@ When troubleshooting:
|
|
|
1117
1131
|
if (type === 'mcp' && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
1118
1132
|
// Execute MCP tool
|
|
1119
1133
|
try {
|
|
1120
|
-
|
|
1134
|
+
// Log MCP tool execution in debug mode
|
|
1135
|
+
if (this.debug) {
|
|
1136
|
+
console.error(`\n[DEBUG] ========================================`);
|
|
1137
|
+
console.error(`[DEBUG] Executing MCP tool: ${toolName}`);
|
|
1138
|
+
console.error(`[DEBUG] Arguments:`);
|
|
1139
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1140
|
+
const displayValue = typeof value === 'string' && value.length > 100
|
|
1141
|
+
? value.substring(0, 100) + '...'
|
|
1142
|
+
: value;
|
|
1143
|
+
console.error(`[DEBUG] ${key}: ${JSON.stringify(displayValue)}`);
|
|
1144
|
+
}
|
|
1145
|
+
console.error(`[DEBUG] ========================================\n`);
|
|
1146
|
+
}
|
|
1121
1147
|
|
|
1122
1148
|
// Execute MCP tool through the bridge
|
|
1123
1149
|
const executionResult = await this.mcpBridge.mcpTools[toolName].execute(params);
|
|
1124
1150
|
|
|
1125
1151
|
const toolResultContent = typeof executionResult === 'string' ? executionResult : JSON.stringify(executionResult, null, 2);
|
|
1126
|
-
|
|
1152
|
+
|
|
1153
|
+
// Log MCP tool result in debug mode
|
|
1127
1154
|
if (this.debug) {
|
|
1128
|
-
|
|
1155
|
+
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + '...' : toolResultContent;
|
|
1156
|
+
console.error(`[DEBUG] ========================================`);
|
|
1157
|
+
console.error(`[DEBUG] MCP tool '${toolName}' completed successfully`);
|
|
1158
|
+
console.error(`[DEBUG] Result preview:`);
|
|
1159
|
+
console.error(preview);
|
|
1160
|
+
console.error(`[DEBUG] ========================================\n`);
|
|
1129
1161
|
}
|
|
1130
1162
|
|
|
1131
1163
|
currentMessages.push({ role: 'user', content: `<tool_result>\n${toolResultContent}\n</tool_result>` });
|
|
1132
1164
|
} catch (error) {
|
|
1133
1165
|
console.error(`Error executing MCP tool ${toolName}:`, error);
|
|
1134
1166
|
const toolResultContent = `Error executing MCP tool ${toolName}: ${error.message}`;
|
|
1135
|
-
|
|
1167
|
+
|
|
1168
|
+
// Log MCP tool error in debug mode
|
|
1169
|
+
if (this.debug) {
|
|
1170
|
+
console.error(`[DEBUG] ========================================`);
|
|
1171
|
+
console.error(`[DEBUG] MCP tool '${toolName}' failed with error:`);
|
|
1172
|
+
console.error(`[DEBUG] ${error.message}`);
|
|
1173
|
+
console.error(`[DEBUG] ========================================\n`);
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1136
1176
|
currentMessages.push({ role: 'user', content: `<tool_result>\n${toolResultContent}\n</tool_result>` });
|
|
1137
1177
|
}
|
|
1138
1178
|
} else if (this.toolImplementations[toolName]) {
|
|
1139
1179
|
// Execute native tool
|
|
1140
1180
|
try {
|
|
1141
1181
|
// Add sessionId and workingDirectory to params for tool execution
|
|
1142
|
-
const toolParams = {
|
|
1143
|
-
...params,
|
|
1182
|
+
const toolParams = {
|
|
1183
|
+
...params,
|
|
1144
1184
|
sessionId: this.sessionId,
|
|
1145
1185
|
workingDirectory: (this.allowedFolders && this.allowedFolders[0]) || process.cwd()
|
|
1146
1186
|
};
|
|
1147
|
-
|
|
1187
|
+
|
|
1188
|
+
// Log tool execution in debug mode
|
|
1189
|
+
if (this.debug) {
|
|
1190
|
+
console.error(`\n[DEBUG] ========================================`);
|
|
1191
|
+
console.error(`[DEBUG] Executing tool: ${toolName}`);
|
|
1192
|
+
console.error(`[DEBUG] Arguments:`);
|
|
1193
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1194
|
+
const displayValue = typeof value === 'string' && value.length > 100
|
|
1195
|
+
? value.substring(0, 100) + '...'
|
|
1196
|
+
: value;
|
|
1197
|
+
console.error(`[DEBUG] ${key}: ${JSON.stringify(displayValue)}`);
|
|
1198
|
+
}
|
|
1199
|
+
console.error(`[DEBUG] ========================================\n`);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1148
1202
|
// Emit tool start event
|
|
1149
1203
|
this.events.emit('toolCall', {
|
|
1150
1204
|
timestamp: new Date().toISOString(),
|
|
@@ -1196,6 +1250,18 @@ When troubleshooting:
|
|
|
1196
1250
|
toolResult = await executeToolCall();
|
|
1197
1251
|
}
|
|
1198
1252
|
|
|
1253
|
+
// Log tool result in debug mode
|
|
1254
|
+
if (this.debug) {
|
|
1255
|
+
const resultPreview = typeof toolResult === 'string'
|
|
1256
|
+
? (toolResult.length > 500 ? toolResult.substring(0, 500) + '...' : toolResult)
|
|
1257
|
+
: (toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + '...' : 'No Result');
|
|
1258
|
+
console.error(`[DEBUG] ========================================`);
|
|
1259
|
+
console.error(`[DEBUG] Tool '${toolName}' completed successfully`);
|
|
1260
|
+
console.error(`[DEBUG] Result preview:`);
|
|
1261
|
+
console.error(resultPreview);
|
|
1262
|
+
console.error(`[DEBUG] ========================================\n`);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1199
1265
|
// Emit tool success event
|
|
1200
1266
|
this.events.emit('toolCall', {
|
|
1201
1267
|
timestamp: new Date().toISOString(),
|
|
@@ -1206,8 +1272,16 @@ When troubleshooting:
|
|
|
1206
1272
|
: (toolResult ? JSON.stringify(toolResult).substring(0, 200) + '...' : 'No Result'),
|
|
1207
1273
|
status: 'completed'
|
|
1208
1274
|
});
|
|
1209
|
-
|
|
1275
|
+
|
|
1210
1276
|
} catch (toolError) {
|
|
1277
|
+
// Log tool error in debug mode
|
|
1278
|
+
if (this.debug) {
|
|
1279
|
+
console.error(`[DEBUG] ========================================`);
|
|
1280
|
+
console.error(`[DEBUG] Tool '${toolName}' failed with error:`);
|
|
1281
|
+
console.error(`[DEBUG] ${toolError.message}`);
|
|
1282
|
+
console.error(`[DEBUG] ========================================\n`);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1211
1285
|
// Emit tool error event
|
|
1212
1286
|
this.events.emit('toolCall', {
|
|
1213
1287
|
timestamp: new Date().toISOString(),
|
|
@@ -1262,7 +1336,23 @@ When troubleshooting:
|
|
|
1262
1336
|
}
|
|
1263
1337
|
}
|
|
1264
1338
|
} else {
|
|
1265
|
-
// No tool call found
|
|
1339
|
+
// No tool call found
|
|
1340
|
+
// Special case: If response contains a mermaid code block and no schema was provided,
|
|
1341
|
+
// treat it as a valid completion (for mermaid diagram fixing workflow)
|
|
1342
|
+
const hasMermaidCodeBlock = /```mermaid\s*\n[\s\S]*?\n```/.test(assistantResponseContent);
|
|
1343
|
+
const hasNoSchemaOrTools = !options.schema && validTools.length === 0;
|
|
1344
|
+
|
|
1345
|
+
if (hasMermaidCodeBlock && hasNoSchemaOrTools) {
|
|
1346
|
+
// Accept mermaid code block as final answer for diagram fixing
|
|
1347
|
+
finalResult = assistantResponseContent;
|
|
1348
|
+
completionAttempted = true;
|
|
1349
|
+
if (this.debug) {
|
|
1350
|
+
console.error(`[DEBUG] Accepting mermaid code block as valid completion (no schema, no tools)`);
|
|
1351
|
+
}
|
|
1352
|
+
break;
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// Add assistant response and ask for tool usage
|
|
1266
1356
|
currentMessages.push({ role: 'assistant', content: assistantResponseContent });
|
|
1267
1357
|
|
|
1268
1358
|
// Build appropriate reminder message based on whether schema is provided
|
package/src/agent/probeTool.js
CHANGED
|
@@ -213,45 +213,99 @@ export function createWrappedTools(baseTools) {
|
|
|
213
213
|
return wrappedTools;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
// Simple file listing tool
|
|
216
|
+
// Simple file listing tool with ls-like formatted output
|
|
217
217
|
export const listFilesTool = {
|
|
218
218
|
execute: async (params) => {
|
|
219
219
|
const { directory = '.', workingDirectory } = params;
|
|
220
|
-
|
|
220
|
+
|
|
221
221
|
// Use the provided working directory, or fall back to process.cwd()
|
|
222
222
|
const baseCwd = workingDirectory || process.cwd();
|
|
223
|
-
|
|
223
|
+
|
|
224
224
|
// Security: Validate path to prevent traversal attacks
|
|
225
225
|
const secureBaseDir = path.resolve(baseCwd);
|
|
226
226
|
const targetDir = path.resolve(secureBaseDir, directory);
|
|
227
227
|
if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
228
228
|
throw new Error('Path traversal attempt detected. Access denied.');
|
|
229
229
|
}
|
|
230
|
-
|
|
230
|
+
|
|
231
|
+
const debug = process.env.DEBUG === '1';
|
|
232
|
+
|
|
233
|
+
if (debug) {
|
|
234
|
+
console.log(`[DEBUG] Listing files in directory: ${targetDir}`);
|
|
235
|
+
}
|
|
236
|
+
|
|
231
237
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
238
|
+
// Read the directory contents
|
|
239
|
+
const files = await fsPromises.readdir(targetDir, { withFileTypes: true });
|
|
240
|
+
|
|
241
|
+
// Format size for human readability
|
|
242
|
+
const formatSize = (size) => {
|
|
243
|
+
if (size < 1024) return `${size}B`;
|
|
244
|
+
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}K`;
|
|
245
|
+
if (size < 1024 * 1024 * 1024) return `${(size / (1024 * 1024)).toFixed(1)}M`;
|
|
246
|
+
return `${(size / (1024 * 1024 * 1024)).toFixed(1)}G`;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
// Format the results as ls-style output
|
|
250
|
+
const entries = await Promise.all(files.map(async (file) => {
|
|
251
|
+
const isDirectory = file.isDirectory();
|
|
252
|
+
const fullPath = path.join(targetDir, file.name);
|
|
253
|
+
|
|
254
|
+
let size = 0;
|
|
255
|
+
try {
|
|
256
|
+
const stats = await fsPromises.stat(fullPath);
|
|
257
|
+
size = stats.size;
|
|
258
|
+
} catch (statError) {
|
|
259
|
+
if (debug) {
|
|
260
|
+
console.log(`[DEBUG] Could not stat file ${file.name}:`, statError.message);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return {
|
|
265
|
+
name: file.name,
|
|
266
|
+
isDirectory,
|
|
267
|
+
size
|
|
268
|
+
};
|
|
269
|
+
}));
|
|
270
|
+
|
|
271
|
+
// Sort: directories first, then files, both alphabetically
|
|
272
|
+
entries.sort((a, b) => {
|
|
273
|
+
if (a.isDirectory && !b.isDirectory) return -1;
|
|
274
|
+
if (!a.isDirectory && b.isDirectory) return 1;
|
|
275
|
+
return a.name.localeCompare(b.name);
|
|
237
276
|
});
|
|
238
|
-
|
|
239
|
-
|
|
277
|
+
|
|
278
|
+
// Format entries
|
|
279
|
+
const formatted = entries.map(entry => {
|
|
280
|
+
const type = entry.isDirectory ? 'dir ' : 'file';
|
|
281
|
+
const sizeStr = formatSize(entry.size).padStart(8);
|
|
282
|
+
return `${type} ${sizeStr} ${entry.name}`;
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
if (debug) {
|
|
286
|
+
console.log(`[DEBUG] Found ${entries.length} files/directories in ${targetDir}`);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Return as formatted text output
|
|
290
|
+
const header = `${targetDir}:\n`;
|
|
291
|
+
const output = header + formatted.join('\n');
|
|
292
|
+
|
|
293
|
+
return output;
|
|
240
294
|
} catch (error) {
|
|
241
295
|
throw new Error(`Failed to list files: ${error.message}`);
|
|
242
296
|
}
|
|
243
297
|
}
|
|
244
298
|
};
|
|
245
299
|
|
|
246
|
-
// Simple file search tool
|
|
300
|
+
// Simple file search tool with timeout protection
|
|
247
301
|
export const searchFilesTool = {
|
|
248
302
|
execute: async (params) => {
|
|
249
303
|
const { pattern, directory = '.', recursive = true, workingDirectory } = params;
|
|
250
|
-
|
|
304
|
+
|
|
251
305
|
if (!pattern) {
|
|
252
306
|
throw new Error('Pattern is required for file search');
|
|
253
307
|
}
|
|
254
|
-
|
|
308
|
+
|
|
255
309
|
// Security: Validate path to prevent traversal attacks
|
|
256
310
|
const baseCwd = workingDirectory || process.cwd();
|
|
257
311
|
const secureBaseDir = path.resolve(baseCwd);
|
|
@@ -259,19 +313,40 @@ export const searchFilesTool = {
|
|
|
259
313
|
if (!targetDir.startsWith(secureBaseDir + path.sep) && targetDir !== secureBaseDir) {
|
|
260
314
|
throw new Error('Path traversal attempt detected. Access denied.');
|
|
261
315
|
}
|
|
262
|
-
|
|
316
|
+
|
|
317
|
+
// Validate pattern complexity to prevent DoS
|
|
318
|
+
if (pattern.includes('**/**') || pattern.split('*').length > 10) {
|
|
319
|
+
throw new Error('Pattern too complex. Please use a simpler glob pattern.');
|
|
320
|
+
}
|
|
321
|
+
|
|
263
322
|
try {
|
|
264
323
|
const options = {
|
|
265
324
|
cwd: targetDir,
|
|
266
325
|
ignore: ['node_modules/**', '.git/**'],
|
|
267
326
|
absolute: false
|
|
268
327
|
};
|
|
269
|
-
|
|
328
|
+
|
|
270
329
|
if (!recursive) {
|
|
271
330
|
options.deep = 1;
|
|
272
331
|
}
|
|
273
|
-
|
|
274
|
-
|
|
332
|
+
|
|
333
|
+
// Create a timeout promise (10 seconds)
|
|
334
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
335
|
+
setTimeout(() => reject(new Error('Search operation timed out after 10 seconds')), 10000);
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// Race glob against timeout
|
|
339
|
+
const files = await Promise.race([
|
|
340
|
+
glob(pattern, options),
|
|
341
|
+
timeoutPromise
|
|
342
|
+
]);
|
|
343
|
+
|
|
344
|
+
// Limit results to prevent memory issues
|
|
345
|
+
const maxResults = 1000;
|
|
346
|
+
if (files.length > maxResults) {
|
|
347
|
+
return files.slice(0, maxResults);
|
|
348
|
+
}
|
|
349
|
+
|
|
275
350
|
return files;
|
|
276
351
|
} catch (error) {
|
|
277
352
|
throw new Error(`Failed to search files: ${error.message}`);
|
package/src/agent/schemaUtils.js
CHANGED
|
@@ -813,7 +813,7 @@ When presented with a broken Mermaid diagram, analyze it thoroughly and provide
|
|
|
813
813
|
debug: this.options.debug,
|
|
814
814
|
tracer: this.options.tracer,
|
|
815
815
|
allowEdit: this.options.allowEdit,
|
|
816
|
-
maxIterations:
|
|
816
|
+
maxIterations: 10, // Allow more iterations for mermaid fixing to handle complex diagrams
|
|
817
817
|
disableMermaidValidation: true // CRITICAL: Disable mermaid validation in nested agent to prevent infinite recursion
|
|
818
818
|
});
|
|
819
819
|
}
|
package/src/index.js
CHANGED
|
@@ -34,6 +34,7 @@ import { searchTool, queryTool, extractTool, delegateTool } from './tools/vercel
|
|
|
34
34
|
import { bashTool } from './tools/bash.js';
|
|
35
35
|
import { ProbeAgent } from './agent/ProbeAgent.js';
|
|
36
36
|
import { SimpleTelemetry, SimpleAppTracer, initializeSimpleTelemetryFromOptions } from './agent/simpleTelemetry.js';
|
|
37
|
+
import { listFilesToolInstance, searchFilesToolInstance } from './agent/probeTool.js';
|
|
37
38
|
|
|
38
39
|
export {
|
|
39
40
|
search,
|
|
@@ -57,6 +58,9 @@ export {
|
|
|
57
58
|
extractTool,
|
|
58
59
|
delegateTool,
|
|
59
60
|
bashTool,
|
|
61
|
+
// Export tool instances
|
|
62
|
+
listFilesToolInstance,
|
|
63
|
+
searchFilesToolInstance,
|
|
60
64
|
// Export schemas
|
|
61
65
|
searchSchema,
|
|
62
66
|
querySchema,
|