@probelabs/probe 0.6.0-rc168 → 0.6.0-rc170
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 +82 -31
- package/build/agent/imageConfig.js +57 -0
- package/build/agent/index.js +111 -47
- package/build/agent/tools.js +26 -9
- package/cjs/agent/ProbeAgent.cjs +211 -73
- package/cjs/index.cjs +211 -73
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +82 -31
- package/src/agent/imageConfig.js +57 -0
- package/src/agent/tools.js +26 -9
|
@@ -13,11 +13,11 @@ import { randomUUID } from 'crypto';
|
|
|
13
13
|
import { EventEmitter } from 'events';
|
|
14
14
|
import { existsSync } from 'fs';
|
|
15
15
|
import { readFile, stat } from 'fs/promises';
|
|
16
|
-
import { resolve, isAbsolute, dirname } from 'path';
|
|
16
|
+
import { resolve, isAbsolute, dirname, basename, normalize, sep } from 'path';
|
|
17
17
|
import { TokenCounter } from './tokenCounter.js';
|
|
18
18
|
import { InMemoryStorageAdapter } from './storage/InMemoryStorageAdapter.js';
|
|
19
19
|
import { HookManager, HOOK_TYPES } from './hooks/HookManager.js';
|
|
20
|
-
import { SUPPORTED_IMAGE_EXTENSIONS, IMAGE_MIME_TYPES } from './imageConfig.js';
|
|
20
|
+
import { SUPPORTED_IMAGE_EXTENSIONS, IMAGE_MIME_TYPES, isFormatSupportedByProvider } from './imageConfig.js';
|
|
21
21
|
import {
|
|
22
22
|
createTools,
|
|
23
23
|
searchToolDefinition,
|
|
@@ -420,14 +420,20 @@ export class ProbeAgent {
|
|
|
420
420
|
* Initialize tools with configuration
|
|
421
421
|
*/
|
|
422
422
|
initializeTools() {
|
|
423
|
+
const isToolAllowed = (toolName) => this.allowedTools.isEnabled(toolName);
|
|
424
|
+
|
|
423
425
|
const configOptions = {
|
|
424
426
|
sessionId: this.sessionId,
|
|
425
427
|
debug: this.debug,
|
|
426
428
|
defaultPath: this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd(),
|
|
427
429
|
allowedFolders: this.allowedFolders,
|
|
428
430
|
outline: this.outline,
|
|
431
|
+
allowEdit: this.allowEdit,
|
|
432
|
+
enableDelegate: this.enableDelegate,
|
|
429
433
|
enableBash: this.enableBash,
|
|
430
|
-
bashConfig: this.bashConfig
|
|
434
|
+
bashConfig: this.bashConfig,
|
|
435
|
+
allowedTools: this.allowedTools,
|
|
436
|
+
isToolAllowed
|
|
431
437
|
};
|
|
432
438
|
|
|
433
439
|
// Create base tools
|
|
@@ -436,21 +442,54 @@ export class ProbeAgent {
|
|
|
436
442
|
// Create wrapped tools with event emission
|
|
437
443
|
const wrappedTools = createWrappedTools(baseTools);
|
|
438
444
|
|
|
439
|
-
// Store tool instances for execution
|
|
440
|
-
this.toolImplementations = {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
445
|
+
// Store tool instances for execution (respect allowedTools + feature flags)
|
|
446
|
+
this.toolImplementations = {};
|
|
447
|
+
|
|
448
|
+
if (wrappedTools.searchToolInstance && isToolAllowed('search')) {
|
|
449
|
+
this.toolImplementations.search = wrappedTools.searchToolInstance;
|
|
450
|
+
}
|
|
451
|
+
if (wrappedTools.queryToolInstance && isToolAllowed('query')) {
|
|
452
|
+
this.toolImplementations.query = wrappedTools.queryToolInstance;
|
|
453
|
+
}
|
|
454
|
+
if (wrappedTools.extractToolInstance && isToolAllowed('extract')) {
|
|
455
|
+
this.toolImplementations.extract = wrappedTools.extractToolInstance;
|
|
456
|
+
}
|
|
457
|
+
if (this.enableDelegate && wrappedTools.delegateToolInstance && isToolAllowed('delegate')) {
|
|
458
|
+
this.toolImplementations.delegate = wrappedTools.delegateToolInstance;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// File browsing tools
|
|
462
|
+
if (isToolAllowed('listFiles')) {
|
|
463
|
+
this.toolImplementations.listFiles = listFilesToolInstance;
|
|
464
|
+
}
|
|
465
|
+
if (isToolAllowed('searchFiles')) {
|
|
466
|
+
this.toolImplementations.searchFiles = searchFilesToolInstance;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// Image loading tool
|
|
470
|
+
if (isToolAllowed('readImage')) {
|
|
471
|
+
this.toolImplementations.readImage = {
|
|
448
472
|
execute: async (params) => {
|
|
449
473
|
const imagePath = params.path;
|
|
450
474
|
if (!imagePath) {
|
|
451
475
|
throw new Error('Image path is required');
|
|
452
476
|
}
|
|
453
477
|
|
|
478
|
+
// Validate extension before attempting to load
|
|
479
|
+
// Use basename to prevent path traversal attacks (e.g., 'malicious.jpg/../../../etc/passwd')
|
|
480
|
+
const filename = basename(imagePath);
|
|
481
|
+
const extension = filename.toLowerCase().split('.').pop();
|
|
482
|
+
|
|
483
|
+
// Always validate extension is in allowed list (defense-in-depth)
|
|
484
|
+
if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
|
|
485
|
+
throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(', ')}`);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// Check provider-specific format restrictions (e.g., SVG not supported by Google Gemini)
|
|
489
|
+
if (this.apiType && !isFormatSupportedByProvider(extension, this.apiType)) {
|
|
490
|
+
throw new Error(`Image format '${extension}' is not supported by the current AI provider (${this.apiType}). Try using a different image format like PNG or JPEG.`);
|
|
491
|
+
}
|
|
492
|
+
|
|
454
493
|
// Load the image using the existing loadImageIfValid method
|
|
455
494
|
const loaded = await this.loadImageIfValid(imagePath);
|
|
456
495
|
|
|
@@ -460,20 +499,20 @@ export class ProbeAgent {
|
|
|
460
499
|
|
|
461
500
|
return `Image loaded successfully: ${imagePath}. The image is now available for analysis in the conversation.`;
|
|
462
501
|
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
502
|
+
};
|
|
503
|
+
}
|
|
465
504
|
|
|
466
|
-
// Add bash tool if enabled
|
|
467
|
-
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
505
|
+
// Add bash tool if enabled and allowed
|
|
506
|
+
if (this.enableBash && wrappedTools.bashToolInstance && isToolAllowed('bash')) {
|
|
468
507
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
469
508
|
}
|
|
470
509
|
|
|
471
|
-
// Add edit and create tools if enabled
|
|
510
|
+
// Add edit and create tools if enabled and allowed
|
|
472
511
|
if (this.allowEdit) {
|
|
473
|
-
if (wrappedTools.editToolInstance) {
|
|
512
|
+
if (wrappedTools.editToolInstance && isToolAllowed('edit')) {
|
|
474
513
|
this.toolImplementations.edit = wrappedTools.editToolInstance;
|
|
475
514
|
}
|
|
476
|
-
if (wrappedTools.createToolInstance) {
|
|
515
|
+
if (wrappedTools.createToolInstance && isToolAllowed('create')) {
|
|
477
516
|
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
478
517
|
}
|
|
479
518
|
}
|
|
@@ -1238,20 +1277,28 @@ export class ProbeAgent {
|
|
|
1238
1277
|
}
|
|
1239
1278
|
|
|
1240
1279
|
// Security validation: check if path is within any allowed directory
|
|
1280
|
+
// Use normalize() after resolve() to handle path traversal attempts (e.g., '/allowed/../etc/passwd')
|
|
1241
1281
|
const allowedDirs = this.allowedFolders && this.allowedFolders.length > 0 ? this.allowedFolders : [process.cwd()];
|
|
1242
|
-
|
|
1282
|
+
|
|
1243
1283
|
let absolutePath;
|
|
1244
1284
|
let isPathAllowed = false;
|
|
1245
|
-
|
|
1285
|
+
|
|
1246
1286
|
// If absolute path, check if it's within any allowed directory
|
|
1247
1287
|
if (isAbsolute(imagePath)) {
|
|
1248
|
-
|
|
1249
|
-
|
|
1288
|
+
// Normalize to resolve any '..' sequences
|
|
1289
|
+
absolutePath = normalize(resolve(imagePath));
|
|
1290
|
+
isPathAllowed = allowedDirs.some(dir => {
|
|
1291
|
+
const normalizedDir = normalize(resolve(dir));
|
|
1292
|
+
// Ensure the path is within the allowed directory (add separator to prevent prefix attacks)
|
|
1293
|
+
return absolutePath === normalizedDir || absolutePath.startsWith(normalizedDir + sep);
|
|
1294
|
+
});
|
|
1250
1295
|
} else {
|
|
1251
1296
|
// For relative paths, try resolving against each allowed directory
|
|
1252
1297
|
for (const dir of allowedDirs) {
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1298
|
+
const normalizedDir = normalize(resolve(dir));
|
|
1299
|
+
const resolvedPath = normalize(resolve(dir, imagePath));
|
|
1300
|
+
// Ensure the resolved path is within the allowed directory
|
|
1301
|
+
if (resolvedPath === normalizedDir || resolvedPath.startsWith(normalizedDir + sep)) {
|
|
1255
1302
|
absolutePath = resolvedPath;
|
|
1256
1303
|
isPathAllowed = true;
|
|
1257
1304
|
break;
|
|
@@ -1295,6 +1342,10 @@ export class ProbeAgent {
|
|
|
1295
1342
|
return false;
|
|
1296
1343
|
}
|
|
1297
1344
|
|
|
1345
|
+
// Note: Provider-specific format validation (e.g., SVG not supported by Google Gemini)
|
|
1346
|
+
// is handled by the readImage tool which provides explicit error messages.
|
|
1347
|
+
// loadImageIfValid is a lower-level method that only checks general format support.
|
|
1348
|
+
|
|
1298
1349
|
// Determine MIME type (from shared config)
|
|
1299
1350
|
const mimeType = IMAGE_MIME_TYPES[extension];
|
|
1300
1351
|
|
|
@@ -2480,7 +2531,7 @@ When troubleshooting:
|
|
|
2480
2531
|
maxIterations,
|
|
2481
2532
|
parentSessionId: this.sessionId, // Pass parent session ID for tracking
|
|
2482
2533
|
path: this.searchPath, // Inherit search path
|
|
2483
|
-
provider: this.
|
|
2534
|
+
provider: this.apiType, // Inherit AI provider (string identifier)
|
|
2484
2535
|
model: this.model, // Inherit model
|
|
2485
2536
|
debug: this.debug,
|
|
2486
2537
|
tracer: this.tracer
|
|
@@ -2489,7 +2540,7 @@ When troubleshooting:
|
|
|
2489
2540
|
if (this.debug) {
|
|
2490
2541
|
console.log(`[DEBUG] Executing delegate tool at iteration ${currentIteration}/${maxIterations}`);
|
|
2491
2542
|
console.log(`[DEBUG] Parent session: ${this.sessionId}`);
|
|
2492
|
-
console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.
|
|
2543
|
+
console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.apiType}, model=${this.model}`);
|
|
2493
2544
|
console.log(`[DEBUG] Delegate task: ${toolParams.task?.substring(0, 100)}...`);
|
|
2494
2545
|
}
|
|
2495
2546
|
|
|
@@ -2573,10 +2624,10 @@ When troubleshooting:
|
|
|
2573
2624
|
content: toolResultMessage
|
|
2574
2625
|
});
|
|
2575
2626
|
|
|
2576
|
-
//
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2627
|
+
// NOTE: Automatic image processing removed (GitHub issue #305)
|
|
2628
|
+
// Images are now only loaded when the AI explicitly calls the readImage tool
|
|
2629
|
+
// This prevents: 1) implicit behavior that users don't expect
|
|
2630
|
+
// 2) crashes with unsupported MIME types (e.g., SVG on Gemini)
|
|
2580
2631
|
|
|
2581
2632
|
if (this.debug) {
|
|
2582
2633
|
console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === 'string' ? toolResult.length : JSON.stringify(toolResult).length}`);
|
|
@@ -21,6 +21,12 @@ export const IMAGE_MIME_TYPES = {
|
|
|
21
21
|
'svg': 'image/svg+xml'
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
// Provider-specific unsupported image formats
|
|
25
|
+
// These providers do not support certain MIME types and will crash if they receive them
|
|
26
|
+
export const PROVIDER_UNSUPPORTED_FORMATS = {
|
|
27
|
+
'google': ['svg'], // Google Gemini doesn't support image/svg+xml
|
|
28
|
+
};
|
|
29
|
+
|
|
24
30
|
/**
|
|
25
31
|
* Generate a regex pattern string for matching image file extensions
|
|
26
32
|
* @param {string[]} extensions - Array of extensions (without dots)
|
|
@@ -38,3 +44,54 @@ export function getExtensionPattern(extensions = SUPPORTED_IMAGE_EXTENSIONS) {
|
|
|
38
44
|
export function getMimeType(extension) {
|
|
39
45
|
return IMAGE_MIME_TYPES[extension.toLowerCase()];
|
|
40
46
|
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if an image extension is supported by a specific provider
|
|
50
|
+
* @param {string} extension - File extension (without dot)
|
|
51
|
+
* @param {string} provider - Provider name (e.g., 'google', 'anthropic', 'openai')
|
|
52
|
+
* @returns {boolean} True if the format is supported by the provider
|
|
53
|
+
*/
|
|
54
|
+
export function isFormatSupportedByProvider(extension, provider) {
|
|
55
|
+
// Validate extension parameter - must be a non-empty string without path separators
|
|
56
|
+
if (!extension || typeof extension !== 'string') {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// Sanitize: reject extensions containing path traversal characters
|
|
60
|
+
if (extension.includes('/') || extension.includes('\\') || extension.includes('..')) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const ext = extension.toLowerCase();
|
|
65
|
+
|
|
66
|
+
// First check if it's a generally supported format
|
|
67
|
+
if (!SUPPORTED_IMAGE_EXTENSIONS.includes(ext)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Handle null/undefined provider gracefully (treat as no restrictions)
|
|
72
|
+
if (!provider || typeof provider !== 'string') {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check provider-specific restrictions
|
|
77
|
+
const unsupportedFormats = PROVIDER_UNSUPPORTED_FORMATS[provider];
|
|
78
|
+
if (unsupportedFormats && unsupportedFormats.includes(ext)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Get supported image extensions for a specific provider
|
|
87
|
+
* @param {string} provider - Provider name (e.g., 'google', 'anthropic', 'openai')
|
|
88
|
+
* @returns {string[]} Array of supported extensions for this provider
|
|
89
|
+
*/
|
|
90
|
+
export function getSupportedExtensionsForProvider(provider) {
|
|
91
|
+
// Handle null/undefined/non-string provider gracefully (return all extensions)
|
|
92
|
+
if (!provider || typeof provider !== 'string') {
|
|
93
|
+
return [...SUPPORTED_IMAGE_EXTENSIONS];
|
|
94
|
+
}
|
|
95
|
+
const unsupportedFormats = PROVIDER_UNSUPPORTED_FORMATS[provider] || [];
|
|
96
|
+
return SUPPORTED_IMAGE_EXTENSIONS.filter(ext => !unsupportedFormats.includes(ext));
|
|
97
|
+
}
|
package/build/agent/index.js
CHANGED
|
@@ -1998,7 +1998,27 @@ var init_HookManager = __esm({
|
|
|
1998
1998
|
});
|
|
1999
1999
|
|
|
2000
2000
|
// src/agent/imageConfig.js
|
|
2001
|
-
|
|
2001
|
+
function isFormatSupportedByProvider(extension, provider) {
|
|
2002
|
+
if (!extension || typeof extension !== "string") {
|
|
2003
|
+
return false;
|
|
2004
|
+
}
|
|
2005
|
+
if (extension.includes("/") || extension.includes("\\") || extension.includes("..")) {
|
|
2006
|
+
return false;
|
|
2007
|
+
}
|
|
2008
|
+
const ext2 = extension.toLowerCase();
|
|
2009
|
+
if (!SUPPORTED_IMAGE_EXTENSIONS.includes(ext2)) {
|
|
2010
|
+
return false;
|
|
2011
|
+
}
|
|
2012
|
+
if (!provider || typeof provider !== "string") {
|
|
2013
|
+
return true;
|
|
2014
|
+
}
|
|
2015
|
+
const unsupportedFormats = PROVIDER_UNSUPPORTED_FORMATS[provider];
|
|
2016
|
+
if (unsupportedFormats && unsupportedFormats.includes(ext2)) {
|
|
2017
|
+
return false;
|
|
2018
|
+
}
|
|
2019
|
+
return true;
|
|
2020
|
+
}
|
|
2021
|
+
var SUPPORTED_IMAGE_EXTENSIONS, IMAGE_MIME_TYPES, PROVIDER_UNSUPPORTED_FORMATS;
|
|
2002
2022
|
var init_imageConfig = __esm({
|
|
2003
2023
|
"src/agent/imageConfig.js"() {
|
|
2004
2024
|
"use strict";
|
|
@@ -2011,6 +2031,10 @@ var init_imageConfig = __esm({
|
|
|
2011
2031
|
"bmp": "image/bmp",
|
|
2012
2032
|
"svg": "image/svg+xml"
|
|
2013
2033
|
};
|
|
2034
|
+
PROVIDER_UNSUPPORTED_FORMATS = {
|
|
2035
|
+
"google": ["svg"]
|
|
2036
|
+
// Google Gemini doesn't support image/svg+xml
|
|
2037
|
+
};
|
|
2014
2038
|
}
|
|
2015
2039
|
});
|
|
2016
2040
|
|
|
@@ -15373,7 +15397,7 @@ var init_esm4 = __esm({
|
|
|
15373
15397
|
*
|
|
15374
15398
|
* @internal
|
|
15375
15399
|
*/
|
|
15376
|
-
constructor(cwd = process.cwd(), pathImpl,
|
|
15400
|
+
constructor(cwd = process.cwd(), pathImpl, sep4, { nocase, childrenCacheSize = 16 * 1024, fs: fs8 = defaultFS } = {}) {
|
|
15377
15401
|
this.#fs = fsFromOption(fs8);
|
|
15378
15402
|
if (cwd instanceof URL || cwd.startsWith("file://")) {
|
|
15379
15403
|
cwd = fileURLToPath4(cwd);
|
|
@@ -15384,7 +15408,7 @@ var init_esm4 = __esm({
|
|
|
15384
15408
|
this.#resolveCache = new ResolveCache();
|
|
15385
15409
|
this.#resolvePosixCache = new ResolveCache();
|
|
15386
15410
|
this.#children = new ChildrenCache(childrenCacheSize);
|
|
15387
|
-
const split = cwdPath.substring(this.rootPath.length).split(
|
|
15411
|
+
const split = cwdPath.substring(this.rootPath.length).split(sep4);
|
|
15388
15412
|
if (split.length === 1 && !split[0]) {
|
|
15389
15413
|
split.pop();
|
|
15390
15414
|
}
|
|
@@ -17550,17 +17574,30 @@ var init_xmlParsingUtils = __esm({
|
|
|
17550
17574
|
// src/agent/tools.js
|
|
17551
17575
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
17552
17576
|
function createTools(configOptions) {
|
|
17553
|
-
const tools2 = {
|
|
17554
|
-
|
|
17555
|
-
|
|
17556
|
-
|
|
17557
|
-
|
|
17558
|
-
|
|
17559
|
-
|
|
17577
|
+
const tools2 = {};
|
|
17578
|
+
const isToolAllowed = configOptions.isToolAllowed || ((toolName) => {
|
|
17579
|
+
if (!configOptions.allowedTools) return true;
|
|
17580
|
+
return configOptions.allowedTools.isEnabled(toolName);
|
|
17581
|
+
});
|
|
17582
|
+
if (isToolAllowed("search")) {
|
|
17583
|
+
tools2.searchTool = searchTool(configOptions);
|
|
17584
|
+
}
|
|
17585
|
+
if (isToolAllowed("query")) {
|
|
17586
|
+
tools2.queryTool = queryTool(configOptions);
|
|
17587
|
+
}
|
|
17588
|
+
if (isToolAllowed("extract")) {
|
|
17589
|
+
tools2.extractTool = extractTool(configOptions);
|
|
17590
|
+
}
|
|
17591
|
+
if (configOptions.enableDelegate && isToolAllowed("delegate")) {
|
|
17592
|
+
tools2.delegateTool = delegateTool(configOptions);
|
|
17593
|
+
}
|
|
17594
|
+
if (configOptions.enableBash && isToolAllowed("bash")) {
|
|
17560
17595
|
tools2.bashTool = bashTool(configOptions);
|
|
17561
17596
|
}
|
|
17562
|
-
if (configOptions.allowEdit) {
|
|
17597
|
+
if (configOptions.allowEdit && isToolAllowed("edit")) {
|
|
17563
17598
|
tools2.editTool = editTool(configOptions);
|
|
17599
|
+
}
|
|
17600
|
+
if (configOptions.allowEdit && isToolAllowed("create")) {
|
|
17564
17601
|
tools2.createTool = createTool(configOptions);
|
|
17565
17602
|
}
|
|
17566
17603
|
return tools2;
|
|
@@ -36287,7 +36324,7 @@ var init_graph_builder = __esm({
|
|
|
36287
36324
|
applyLinkStyles() {
|
|
36288
36325
|
if (!this.pendingLinkStyles.length || !this.edges.length)
|
|
36289
36326
|
return;
|
|
36290
|
-
const
|
|
36327
|
+
const normalize3 = (s) => {
|
|
36291
36328
|
const out = {};
|
|
36292
36329
|
for (const [kRaw, vRaw] of Object.entries(s)) {
|
|
36293
36330
|
const k = kRaw.trim().toLowerCase();
|
|
@@ -36308,7 +36345,7 @@ var init_graph_builder = __esm({
|
|
|
36308
36345
|
return out;
|
|
36309
36346
|
};
|
|
36310
36347
|
for (const cmd of this.pendingLinkStyles) {
|
|
36311
|
-
const style =
|
|
36348
|
+
const style = normalize3(cmd.props);
|
|
36312
36349
|
for (const idx of cmd.indices) {
|
|
36313
36350
|
if (idx >= 0 && idx < this.edges.length) {
|
|
36314
36351
|
const e = this.edges[idx];
|
|
@@ -43400,7 +43437,7 @@ var require_bk = __commonJS({
|
|
|
43400
43437
|
return xs;
|
|
43401
43438
|
}
|
|
43402
43439
|
function buildBlockGraph(g, layering, root2, reverseSep) {
|
|
43403
|
-
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn =
|
|
43440
|
+
var blockGraph = new Graph(), graphLabel = g.graph(), sepFn = sep4(graphLabel.nodesep, graphLabel.edgesep, reverseSep);
|
|
43404
43441
|
_.forEach(layering, function(layer) {
|
|
43405
43442
|
var u;
|
|
43406
43443
|
_.forEach(layer, function(v) {
|
|
@@ -43490,7 +43527,7 @@ var require_bk = __commonJS({
|
|
|
43490
43527
|
alignCoordinates(xss, smallestWidth);
|
|
43491
43528
|
return balance(xss, g.graph().align);
|
|
43492
43529
|
}
|
|
43493
|
-
function
|
|
43530
|
+
function sep4(nodeSep, edgeSep, reverseSep) {
|
|
43494
43531
|
return function(g, v, w) {
|
|
43495
43532
|
var vLabel = g.node(v);
|
|
43496
43533
|
var wLabel = g.node(w);
|
|
@@ -43575,7 +43612,7 @@ var require_layout = __commonJS({
|
|
|
43575
43612
|
"use strict";
|
|
43576
43613
|
var _ = require_lodash2();
|
|
43577
43614
|
var acyclic = require_acyclic();
|
|
43578
|
-
var
|
|
43615
|
+
var normalize3 = require_normalize();
|
|
43579
43616
|
var rank = require_rank();
|
|
43580
43617
|
var normalizeRanks = require_util().normalizeRanks;
|
|
43581
43618
|
var parentDummyChains = require_parent_dummy_chains();
|
|
@@ -43637,7 +43674,7 @@ var require_layout = __commonJS({
|
|
|
43637
43674
|
removeEdgeLabelProxies(g);
|
|
43638
43675
|
});
|
|
43639
43676
|
time(" normalize.run", function() {
|
|
43640
|
-
|
|
43677
|
+
normalize3.run(g);
|
|
43641
43678
|
});
|
|
43642
43679
|
time(" parentDummyChains", function() {
|
|
43643
43680
|
parentDummyChains(g);
|
|
@@ -43664,7 +43701,7 @@ var require_layout = __commonJS({
|
|
|
43664
43701
|
removeBorderNodes(g);
|
|
43665
43702
|
});
|
|
43666
43703
|
time(" normalize.undo", function() {
|
|
43667
|
-
|
|
43704
|
+
normalize3.undo(g);
|
|
43668
43705
|
});
|
|
43669
43706
|
time(" fixupEdgeLabelCoords", function() {
|
|
43670
43707
|
fixupEdgeLabelCoords(g);
|
|
@@ -50035,8 +50072,8 @@ var require_resolve = __commonJS({
|
|
|
50035
50072
|
}
|
|
50036
50073
|
return count;
|
|
50037
50074
|
}
|
|
50038
|
-
function getFullPath(resolver, id = "",
|
|
50039
|
-
if (
|
|
50075
|
+
function getFullPath(resolver, id = "", normalize3) {
|
|
50076
|
+
if (normalize3 !== false)
|
|
50040
50077
|
id = normalizeId(id);
|
|
50041
50078
|
const p = resolver.parse(id);
|
|
50042
50079
|
return _getFullPath(resolver, p);
|
|
@@ -51376,7 +51413,7 @@ var require_fast_uri = __commonJS({
|
|
|
51376
51413
|
"use strict";
|
|
51377
51414
|
var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
|
|
51378
51415
|
var { SCHEMES, getSchemeHandler } = require_schemes();
|
|
51379
|
-
function
|
|
51416
|
+
function normalize3(uri, options) {
|
|
51380
51417
|
if (typeof uri === "string") {
|
|
51381
51418
|
uri = /** @type {T} */
|
|
51382
51419
|
serialize(parse6(uri, options), options);
|
|
@@ -51612,7 +51649,7 @@ var require_fast_uri = __commonJS({
|
|
|
51612
51649
|
}
|
|
51613
51650
|
var fastUri = {
|
|
51614
51651
|
SCHEMES,
|
|
51615
|
-
normalize:
|
|
51652
|
+
normalize: normalize3,
|
|
51616
51653
|
resolve: resolve6,
|
|
51617
51654
|
resolveComponent,
|
|
51618
51655
|
equal,
|
|
@@ -58980,7 +59017,7 @@ import { randomUUID as randomUUID5 } from "crypto";
|
|
|
58980
59017
|
import { EventEmitter as EventEmitter5 } from "events";
|
|
58981
59018
|
import { existsSync as existsSync5 } from "fs";
|
|
58982
59019
|
import { readFile, stat } from "fs/promises";
|
|
58983
|
-
import { resolve as resolve4, isAbsolute as isAbsolute2, dirname as dirname4 } from "path";
|
|
59020
|
+
import { resolve as resolve4, isAbsolute as isAbsolute2, dirname as dirname4, basename, normalize as normalize2, sep as sep3 } from "path";
|
|
58984
59021
|
var MAX_TOOL_ITERATIONS, MAX_HISTORY_MESSAGES, MAX_IMAGE_FILE_SIZE, ProbeAgent;
|
|
58985
59022
|
var init_ProbeAgent = __esm({
|
|
58986
59023
|
"src/agent/ProbeAgent.js"() {
|
|
@@ -59264,46 +59301,72 @@ var init_ProbeAgent = __esm({
|
|
|
59264
59301
|
* Initialize tools with configuration
|
|
59265
59302
|
*/
|
|
59266
59303
|
initializeTools() {
|
|
59304
|
+
const isToolAllowed = (toolName) => this.allowedTools.isEnabled(toolName);
|
|
59267
59305
|
const configOptions = {
|
|
59268
59306
|
sessionId: this.sessionId,
|
|
59269
59307
|
debug: this.debug,
|
|
59270
59308
|
defaultPath: this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd(),
|
|
59271
59309
|
allowedFolders: this.allowedFolders,
|
|
59272
59310
|
outline: this.outline,
|
|
59311
|
+
allowEdit: this.allowEdit,
|
|
59312
|
+
enableDelegate: this.enableDelegate,
|
|
59273
59313
|
enableBash: this.enableBash,
|
|
59274
|
-
bashConfig: this.bashConfig
|
|
59314
|
+
bashConfig: this.bashConfig,
|
|
59315
|
+
allowedTools: this.allowedTools,
|
|
59316
|
+
isToolAllowed
|
|
59275
59317
|
};
|
|
59276
59318
|
const baseTools = createTools(configOptions);
|
|
59277
59319
|
const wrappedTools = createWrappedTools(baseTools);
|
|
59278
|
-
this.toolImplementations = {
|
|
59279
|
-
|
|
59280
|
-
|
|
59281
|
-
|
|
59282
|
-
|
|
59283
|
-
|
|
59284
|
-
|
|
59285
|
-
|
|
59320
|
+
this.toolImplementations = {};
|
|
59321
|
+
if (wrappedTools.searchToolInstance && isToolAllowed("search")) {
|
|
59322
|
+
this.toolImplementations.search = wrappedTools.searchToolInstance;
|
|
59323
|
+
}
|
|
59324
|
+
if (wrappedTools.queryToolInstance && isToolAllowed("query")) {
|
|
59325
|
+
this.toolImplementations.query = wrappedTools.queryToolInstance;
|
|
59326
|
+
}
|
|
59327
|
+
if (wrappedTools.extractToolInstance && isToolAllowed("extract")) {
|
|
59328
|
+
this.toolImplementations.extract = wrappedTools.extractToolInstance;
|
|
59329
|
+
}
|
|
59330
|
+
if (this.enableDelegate && wrappedTools.delegateToolInstance && isToolAllowed("delegate")) {
|
|
59331
|
+
this.toolImplementations.delegate = wrappedTools.delegateToolInstance;
|
|
59332
|
+
}
|
|
59333
|
+
if (isToolAllowed("listFiles")) {
|
|
59334
|
+
this.toolImplementations.listFiles = listFilesToolInstance;
|
|
59335
|
+
}
|
|
59336
|
+
if (isToolAllowed("searchFiles")) {
|
|
59337
|
+
this.toolImplementations.searchFiles = searchFilesToolInstance;
|
|
59338
|
+
}
|
|
59339
|
+
if (isToolAllowed("readImage")) {
|
|
59340
|
+
this.toolImplementations.readImage = {
|
|
59286
59341
|
execute: async (params) => {
|
|
59287
59342
|
const imagePath = params.path;
|
|
59288
59343
|
if (!imagePath) {
|
|
59289
59344
|
throw new Error("Image path is required");
|
|
59290
59345
|
}
|
|
59346
|
+
const filename = basename(imagePath);
|
|
59347
|
+
const extension = filename.toLowerCase().split(".").pop();
|
|
59348
|
+
if (!extension || !SUPPORTED_IMAGE_EXTENSIONS.includes(extension)) {
|
|
59349
|
+
throw new Error(`Invalid or unsupported image extension: ${extension}. Supported formats: ${SUPPORTED_IMAGE_EXTENSIONS.join(", ")}`);
|
|
59350
|
+
}
|
|
59351
|
+
if (this.apiType && !isFormatSupportedByProvider(extension, this.apiType)) {
|
|
59352
|
+
throw new Error(`Image format '${extension}' is not supported by the current AI provider (${this.apiType}). Try using a different image format like PNG or JPEG.`);
|
|
59353
|
+
}
|
|
59291
59354
|
const loaded = await this.loadImageIfValid(imagePath);
|
|
59292
59355
|
if (!loaded) {
|
|
59293
59356
|
throw new Error(`Failed to load image: ${imagePath}. The file may not exist, be too large, have an unsupported format, or be outside allowed directories.`);
|
|
59294
59357
|
}
|
|
59295
59358
|
return `Image loaded successfully: ${imagePath}. The image is now available for analysis in the conversation.`;
|
|
59296
59359
|
}
|
|
59297
|
-
}
|
|
59298
|
-
}
|
|
59299
|
-
if (this.enableBash && wrappedTools.bashToolInstance) {
|
|
59360
|
+
};
|
|
59361
|
+
}
|
|
59362
|
+
if (this.enableBash && wrappedTools.bashToolInstance && isToolAllowed("bash")) {
|
|
59300
59363
|
this.toolImplementations.bash = wrappedTools.bashToolInstance;
|
|
59301
59364
|
}
|
|
59302
59365
|
if (this.allowEdit) {
|
|
59303
|
-
if (wrappedTools.editToolInstance) {
|
|
59366
|
+
if (wrappedTools.editToolInstance && isToolAllowed("edit")) {
|
|
59304
59367
|
this.toolImplementations.edit = wrappedTools.editToolInstance;
|
|
59305
59368
|
}
|
|
59306
|
-
if (wrappedTools.createToolInstance) {
|
|
59369
|
+
if (wrappedTools.createToolInstance && isToolAllowed("create")) {
|
|
59307
59370
|
this.toolImplementations.create = wrappedTools.createToolInstance;
|
|
59308
59371
|
}
|
|
59309
59372
|
}
|
|
@@ -59906,12 +59969,16 @@ var init_ProbeAgent = __esm({
|
|
|
59906
59969
|
let absolutePath;
|
|
59907
59970
|
let isPathAllowed2 = false;
|
|
59908
59971
|
if (isAbsolute2(imagePath)) {
|
|
59909
|
-
absolutePath = imagePath;
|
|
59910
|
-
isPathAllowed2 = allowedDirs.some((dir) =>
|
|
59972
|
+
absolutePath = normalize2(resolve4(imagePath));
|
|
59973
|
+
isPathAllowed2 = allowedDirs.some((dir) => {
|
|
59974
|
+
const normalizedDir = normalize2(resolve4(dir));
|
|
59975
|
+
return absolutePath === normalizedDir || absolutePath.startsWith(normalizedDir + sep3);
|
|
59976
|
+
});
|
|
59911
59977
|
} else {
|
|
59912
59978
|
for (const dir of allowedDirs) {
|
|
59913
|
-
const
|
|
59914
|
-
|
|
59979
|
+
const normalizedDir = normalize2(resolve4(dir));
|
|
59980
|
+
const resolvedPath = normalize2(resolve4(dir, imagePath));
|
|
59981
|
+
if (resolvedPath === normalizedDir || resolvedPath.startsWith(normalizedDir + sep3)) {
|
|
59915
59982
|
absolutePath = resolvedPath;
|
|
59916
59983
|
isPathAllowed2 = true;
|
|
59917
59984
|
break;
|
|
@@ -60919,8 +60986,8 @@ ${toolResultContent}
|
|
|
60919
60986
|
// Pass parent session ID for tracking
|
|
60920
60987
|
path: this.searchPath,
|
|
60921
60988
|
// Inherit search path
|
|
60922
|
-
provider: this.
|
|
60923
|
-
// Inherit AI provider
|
|
60989
|
+
provider: this.apiType,
|
|
60990
|
+
// Inherit AI provider (string identifier)
|
|
60924
60991
|
model: this.model,
|
|
60925
60992
|
// Inherit model
|
|
60926
60993
|
debug: this.debug,
|
|
@@ -60929,7 +60996,7 @@ ${toolResultContent}
|
|
|
60929
60996
|
if (this.debug) {
|
|
60930
60997
|
console.log(`[DEBUG] Executing delegate tool at iteration ${currentIteration}/${maxIterations}`);
|
|
60931
60998
|
console.log(`[DEBUG] Parent session: ${this.sessionId}`);
|
|
60932
|
-
console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.
|
|
60999
|
+
console.log(`[DEBUG] Inherited config: path=${this.searchPath}, provider=${this.apiType}, model=${this.model}`);
|
|
60933
61000
|
console.log(`[DEBUG] Delegate task: ${toolParams.task?.substring(0, 100)}...`);
|
|
60934
61001
|
}
|
|
60935
61002
|
if (this.tracer) {
|
|
@@ -60996,9 +61063,6 @@ ${toolResultContent}
|
|
|
60996
61063
|
role: "user",
|
|
60997
61064
|
content: toolResultMessage
|
|
60998
61065
|
});
|
|
60999
|
-
if (toolResultContent) {
|
|
61000
|
-
await this.processImageReferences(toolResultContent);
|
|
61001
|
-
}
|
|
61002
61066
|
if (this.debug) {
|
|
61003
61067
|
console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === "string" ? toolResult.length : JSON.stringify(toolResult).length}`);
|
|
61004
61068
|
}
|
package/build/agent/tools.js
CHANGED
|
@@ -31,21 +31,39 @@ import { processXmlWithThinkingAndRecovery } from './xmlParsingUtils.js';
|
|
|
31
31
|
|
|
32
32
|
// Create configured tool instances
|
|
33
33
|
export function createTools(configOptions) {
|
|
34
|
-
const tools = {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const tools = {};
|
|
35
|
+
|
|
36
|
+
const isToolAllowed =
|
|
37
|
+
configOptions.isToolAllowed ||
|
|
38
|
+
((toolName) => {
|
|
39
|
+
if (!configOptions.allowedTools) return true;
|
|
40
|
+
return configOptions.allowedTools.isEnabled(toolName);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Core tools
|
|
44
|
+
if (isToolAllowed('search')) {
|
|
45
|
+
tools.searchTool = searchTool(configOptions);
|
|
46
|
+
}
|
|
47
|
+
if (isToolAllowed('query')) {
|
|
48
|
+
tools.queryTool = queryTool(configOptions);
|
|
49
|
+
}
|
|
50
|
+
if (isToolAllowed('extract')) {
|
|
51
|
+
tools.extractTool = extractTool(configOptions);
|
|
52
|
+
}
|
|
53
|
+
if (configOptions.enableDelegate && isToolAllowed('delegate')) {
|
|
54
|
+
tools.delegateTool = delegateTool(configOptions);
|
|
55
|
+
}
|
|
40
56
|
|
|
41
57
|
// Add bash tool if enabled
|
|
42
|
-
if (configOptions.enableBash) {
|
|
58
|
+
if (configOptions.enableBash && isToolAllowed('bash')) {
|
|
43
59
|
tools.bashTool = bashTool(configOptions);
|
|
44
60
|
}
|
|
45
61
|
|
|
46
62
|
// Add edit and create tools if enabled
|
|
47
|
-
if (configOptions.allowEdit) {
|
|
63
|
+
if (configOptions.allowEdit && isToolAllowed('edit')) {
|
|
48
64
|
tools.editTool = editTool(configOptions);
|
|
65
|
+
}
|
|
66
|
+
if (configOptions.allowEdit && isToolAllowed('create')) {
|
|
49
67
|
tools.createTool = createTool(configOptions);
|
|
50
68
|
}
|
|
51
69
|
|
|
@@ -199,4 +217,3 @@ export function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
|
199
217
|
// Otherwise, use the original parseXmlToolCall function to parse the cleaned XML string
|
|
200
218
|
return parseXmlToolCall(cleanedXmlString, validTools);
|
|
201
219
|
}
|
|
202
|
-
|