@probelabs/probe 0.6.0-rc164 → 0.6.0-rc166

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.
@@ -27,6 +27,7 @@ import {
27
27
  bashToolDefinition,
28
28
  listFilesToolDefinition,
29
29
  searchFilesToolDefinition,
30
+ readImageToolDefinition,
30
31
  attemptCompletionToolDefinition,
31
32
  implementToolDefinition,
32
33
  editToolDefinition,
@@ -399,6 +400,23 @@ export class ProbeAgent {
399
400
  delegate: wrappedTools.delegateToolInstance,
400
401
  listFiles: listFilesToolInstance,
401
402
  searchFiles: searchFilesToolInstance,
403
+ readImage: {
404
+ execute: async (params) => {
405
+ const imagePath = params.path;
406
+ if (!imagePath) {
407
+ throw new Error('Image path is required');
408
+ }
409
+
410
+ // Load the image using the existing loadImageIfValid method
411
+ const loaded = await this.loadImageIfValid(imagePath);
412
+
413
+ if (!loaded) {
414
+ 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.`);
415
+ }
416
+
417
+ return `Image loaded successfully: ${imagePath}. The image is now available for analysis in the conversation.`;
418
+ }
419
+ }
402
420
  };
403
421
 
404
422
  // Add bash tool if enabled
@@ -1172,6 +1190,9 @@ export class ProbeAgent {
1172
1190
  if (isToolAllowed('searchFiles')) {
1173
1191
  toolDefinitions += `${searchFilesToolDefinition}\n`;
1174
1192
  }
1193
+ if (isToolAllowed('readImage')) {
1194
+ toolDefinitions += `${readImageToolDefinition}\n`;
1195
+ }
1175
1196
 
1176
1197
  // Edit tools (require both allowEdit flag AND allowedTools permission)
1177
1198
  if (this.allowEdit && isToolAllowed('implement')) {
@@ -1262,6 +1283,7 @@ Available Tools:
1262
1283
  - extract: Extract specific code blocks or lines from files.
1263
1284
  - listFiles: List files and directories in a specified location.
1264
1285
  - searchFiles: Find files matching a glob pattern with recursive search capability.
1286
+ - readImage: Read and load an image file for AI analysis.
1265
1287
  ${this.allowEdit ? '- implement: Implement a feature or fix a bug using aider.\n- edit: Edit files using exact string replacement.\n- create: Create new files with specified content.\n' : ''}${this.enableDelegate ? '- delegate: Delegate big distinct tasks to specialized probe subagents.\n' : ''}${this.enableBash ? '- bash: Execute bash commands for system operations.\n' : ''}
1266
1288
  - attempt_completion: Finalize the task and provide the result to the user.
1267
1289
  - attempt_complete: Quick completion using previous response (shorthand).
@@ -1700,22 +1722,30 @@ When troubleshooting:
1700
1722
  console.log(`[DEBUG] Assistant response (${assistantResponseContent.length} chars): ${assistantPreview}`);
1701
1723
  }
1702
1724
 
1703
- // Process image references in assistant response for next iteration
1704
- if (assistantResponseContent) {
1705
- await this.processImageReferences(assistantResponseContent);
1706
- }
1725
+ // Images in assistant responses are not automatically processed
1726
+ // AI can use the readImage tool to explicitly request reading an image
1707
1727
 
1708
1728
  // Parse tool call from response with valid tools list
1709
- const validTools = [
1710
- 'search', 'query', 'extract', 'listFiles', 'searchFiles', 'attempt_completion'
1711
- ];
1712
- if (this.allowEdit) {
1729
+ // Build validTools based on allowedTools configuration (same pattern as getSystemMessage)
1730
+ const validTools = [];
1731
+ if (this.allowedTools.isEnabled('search')) validTools.push('search');
1732
+ if (this.allowedTools.isEnabled('query')) validTools.push('query');
1733
+ if (this.allowedTools.isEnabled('extract')) validTools.push('extract');
1734
+ if (this.allowedTools.isEnabled('listFiles')) validTools.push('listFiles');
1735
+ if (this.allowedTools.isEnabled('searchFiles')) validTools.push('searchFiles');
1736
+ if (this.allowedTools.isEnabled('readImage')) validTools.push('readImage');
1737
+ if (this.allowedTools.isEnabled('attempt_completion')) validTools.push('attempt_completion');
1738
+
1739
+ // Edit tools (require both allowEdit flag AND allowedTools permission)
1740
+ if (this.allowEdit && this.allowedTools.isEnabled('implement')) {
1713
1741
  validTools.push('implement', 'edit', 'create');
1714
1742
  }
1715
- if (this.enableBash) {
1743
+ // Bash tool (require both enableBash flag AND allowedTools permission)
1744
+ if (this.enableBash && this.allowedTools.isEnabled('bash')) {
1716
1745
  validTools.push('bash');
1717
1746
  }
1718
- if (this.enableDelegate) {
1747
+ // Delegate tool (require both enableDelegate flag AND allowedTools permission)
1748
+ if (this.enableDelegate && this.allowedTools.isEnabled('delegate')) {
1719
1749
  validTools.push('delegate');
1720
1750
  }
1721
1751
 
@@ -17572,7 +17572,7 @@ function parseXmlToolCallWithThinking(xmlString, validTools) {
17572
17572
  }
17573
17573
  return parseXmlToolCall(cleanedXmlString, validTools);
17574
17574
  }
17575
- var implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition;
17575
+ var implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, readImageToolDefinition;
17576
17576
  var init_tools2 = __esm({
17577
17577
  "src/agent/tools.js"() {
17578
17578
  "use strict";
@@ -17650,6 +17650,29 @@ User: Find all markdown files in the docs directory, but only at the top level.
17650
17650
  <recursive>false</recursive>
17651
17651
  </searchFiles>
17652
17652
 
17653
+ </examples>
17654
+ `;
17655
+ readImageToolDefinition = `
17656
+ ## readImage
17657
+ Description: Read and load an image file so it can be viewed by the AI. Use this when you need to analyze, describe, or work with image content. Images from user messages are automatically loaded, but use this tool to explicitly read images mentioned in tool outputs or when you need to examine specific image files.
17658
+
17659
+ Parameters:
17660
+ - path: (required) The path to the image file to read. Supports png, jpg, jpeg, webp, bmp, and svg formats.
17661
+
17662
+ Usage Example:
17663
+
17664
+ <examples>
17665
+
17666
+ User: Can you describe what's in screenshot.png?
17667
+ <readImage>
17668
+ <path>screenshot.png</path>
17669
+ </readImage>
17670
+
17671
+ User: Analyze the diagram in docs/architecture.svg
17672
+ <readImage>
17673
+ <path>docs/architecture.svg</path>
17674
+ </readImage>
17675
+
17653
17676
  </examples>
17654
17677
  `;
17655
17678
  }
@@ -54263,6 +54286,7 @@ __export(schemaUtils_exports, {
54263
54286
  createMermaidCorrectionPrompt: () => createMermaidCorrectionPrompt,
54264
54287
  createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
54265
54288
  decodeHtmlEntities: () => decodeHtmlEntities,
54289
+ extractMermaidFromJson: () => extractMermaidFromJson,
54266
54290
  extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
54267
54291
  generateExampleFromSchema: () => generateExampleFromSchema,
54268
54292
  generateSchemaInstructions: () => generateSchemaInstructions,
@@ -54270,6 +54294,7 @@ __export(schemaUtils_exports, {
54270
54294
  isJsonSchemaDefinition: () => isJsonSchemaDefinition,
54271
54295
  isMermaidSchema: () => isMermaidSchema,
54272
54296
  processSchemaResponse: () => processSchemaResponse,
54297
+ replaceMermaidDiagramsInJson: () => replaceMermaidDiagramsInJson,
54273
54298
  replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
54274
54299
  tryMaidAutoFix: () => tryMaidAutoFix,
54275
54300
  validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
@@ -54373,6 +54398,49 @@ function decodeHtmlEntities(text) {
54373
54398
  }
54374
54399
  return decoded;
54375
54400
  }
54401
+ function normalizeJsonQuotes(str) {
54402
+ if (!str || typeof str !== "string") {
54403
+ return str;
54404
+ }
54405
+ if (!str.includes("'")) {
54406
+ return str;
54407
+ }
54408
+ let result = "";
54409
+ let inDoubleQuote = false;
54410
+ let inSingleQuote = false;
54411
+ let escaped = false;
54412
+ for (let i = 0; i < str.length; i++) {
54413
+ const char = str[i];
54414
+ const prevChar = i > 0 ? str[i - 1] : "";
54415
+ if (escaped) {
54416
+ result += char;
54417
+ escaped = false;
54418
+ continue;
54419
+ }
54420
+ if (char === "\\") {
54421
+ escaped = true;
54422
+ result += char;
54423
+ continue;
54424
+ }
54425
+ if (char === '"' && !inSingleQuote) {
54426
+ inDoubleQuote = !inDoubleQuote;
54427
+ result += char;
54428
+ continue;
54429
+ }
54430
+ if (char === "'" && !inDoubleQuote) {
54431
+ if (inSingleQuote) {
54432
+ result += '"';
54433
+ inSingleQuote = false;
54434
+ } else {
54435
+ result += '"';
54436
+ inSingleQuote = true;
54437
+ }
54438
+ continue;
54439
+ }
54440
+ result += char;
54441
+ }
54442
+ return result;
54443
+ }
54376
54444
  function cleanSchemaResponse(response) {
54377
54445
  if (!response || typeof response !== "string") {
54378
54446
  return response;
@@ -54380,23 +54448,27 @@ function cleanSchemaResponse(response) {
54380
54448
  const trimmed = response.trim();
54381
54449
  const jsonBlockMatch = trimmed.match(/```json\s*\n([\s\S]*?)\n```/);
54382
54450
  if (jsonBlockMatch) {
54383
- return jsonBlockMatch[1].trim();
54451
+ return normalizeJsonQuotes(jsonBlockMatch[1].trim());
54384
54452
  }
54385
54453
  const anyBlockMatch = trimmed.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/);
54386
54454
  if (anyBlockMatch) {
54387
- return anyBlockMatch[1].trim();
54455
+ return normalizeJsonQuotes(anyBlockMatch[1].trim());
54388
54456
  }
54389
54457
  const codeBlockPatterns = [
54390
54458
  /```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
54391
- /```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
54392
- /`([{\[][\s\S]*?[}\]])`/
54459
+ /```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/
54393
54460
  ];
54394
54461
  for (const pattern of codeBlockPatterns) {
54395
54462
  const match2 = trimmed.match(pattern);
54396
54463
  if (match2) {
54397
- return match2[1].trim();
54464
+ return normalizeJsonQuotes(match2[1].trim());
54398
54465
  }
54399
54466
  }
54467
+ const singleBacktickPattern = /^`([{\[][\s\S]*?[}\]])`$/;
54468
+ const singleBacktickMatch = trimmed.match(singleBacktickPattern);
54469
+ if (singleBacktickMatch) {
54470
+ return normalizeJsonQuotes(singleBacktickMatch[1].trim());
54471
+ }
54400
54472
  const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
54401
54473
  const codeBlockMatch = trimmed.match(codeBlockStartPattern);
54402
54474
  if (codeBlockMatch) {
@@ -54415,7 +54487,7 @@ function cleanSchemaResponse(response) {
54415
54487
  endIndex++;
54416
54488
  }
54417
54489
  if (bracketCount === 0) {
54418
- return trimmed.substring(startIndex, endIndex);
54490
+ return normalizeJsonQuotes(trimmed.substring(startIndex, endIndex));
54419
54491
  }
54420
54492
  }
54421
54493
  let cleaned = trimmed;
@@ -54427,7 +54499,7 @@ function cleanSchemaResponse(response) {
54427
54499
  const isJsonObject = firstChar === "{" && lastChar === "}";
54428
54500
  const isJsonArray = firstChar === "[" && lastChar === "]";
54429
54501
  if (isJsonObject || isJsonArray) {
54430
- return cleaned;
54502
+ return normalizeJsonQuotes(cleaned);
54431
54503
  }
54432
54504
  return response;
54433
54505
  }
@@ -54837,10 +54909,66 @@ function isMermaidSchema(schema) {
54837
54909
  ];
54838
54910
  return mermaidIndicators.some((indicator) => indicator);
54839
54911
  }
54912
+ function extractMermaidFromJson(response) {
54913
+ if (!response || typeof response !== "string") {
54914
+ return { diagrams: [], jsonPaths: [], parsedJson: null };
54915
+ }
54916
+ let jsonContent = response.trim();
54917
+ const jsonBlockMatch = jsonContent.match(/```json\s*\n([\s\S]*?)\n```/);
54918
+ if (jsonBlockMatch) {
54919
+ jsonContent = jsonBlockMatch[1].trim();
54920
+ } else {
54921
+ const anyBlockMatch = jsonContent.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/);
54922
+ if (anyBlockMatch) {
54923
+ jsonContent = anyBlockMatch[1].trim();
54924
+ }
54925
+ }
54926
+ let parsedJson;
54927
+ try {
54928
+ parsedJson = JSON.parse(jsonContent);
54929
+ } catch (e) {
54930
+ return { diagrams: [], jsonPaths: [], parsedJson: null };
54931
+ }
54932
+ const diagrams = [];
54933
+ const jsonPaths = [];
54934
+ function searchObject(obj, path7 = []) {
54935
+ if (typeof obj === "string") {
54936
+ const mermaidPattern = /```mermaid([^\n`]*?)(?:\n|\\n)([\s\S]*?)```/gi;
54937
+ let match2;
54938
+ while ((match2 = mermaidPattern.exec(obj)) !== null) {
54939
+ const attributes = match2[1] ? match2[1].trim() : "";
54940
+ const content = match2[2].replace(/\\n/g, "\n");
54941
+ diagrams.push({
54942
+ content,
54943
+ fullMatch: match2[0],
54944
+ startIndex: match2.index,
54945
+ endIndex: match2.index + match2[0].length,
54946
+ attributes,
54947
+ isInJson: true,
54948
+ jsonPath: path7.join(".")
54949
+ });
54950
+ jsonPaths.push(path7.join("."));
54951
+ }
54952
+ } else if (Array.isArray(obj)) {
54953
+ obj.forEach((item, index) => searchObject(item, [...path7, `[${index}]`]));
54954
+ } else if (obj && typeof obj === "object") {
54955
+ Object.entries(obj).forEach(([key, value]) => searchObject(value, [...path7, key]));
54956
+ }
54957
+ }
54958
+ searchObject(parsedJson);
54959
+ return { diagrams, jsonPaths, parsedJson };
54960
+ }
54840
54961
  function extractMermaidFromMarkdown(response) {
54841
54962
  if (!response || typeof response !== "string") {
54842
54963
  return { diagrams: [], cleanedResponse: response };
54843
54964
  }
54965
+ const trimmed = response.trim();
54966
+ if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.includes("```json")) {
54967
+ const jsonResult = extractMermaidFromJson(response);
54968
+ if (jsonResult.diagrams.length > 0) {
54969
+ return { diagrams: jsonResult.diagrams, cleanedResponse: response };
54970
+ }
54971
+ }
54844
54972
  const mermaidBlockRegex = /```mermaid([^\n]*)\n([\s\S]*?)```/gi;
54845
54973
  const diagrams = [];
54846
54974
  let match2;
@@ -54852,11 +54980,66 @@ function extractMermaidFromMarkdown(response) {
54852
54980
  fullMatch: match2[0],
54853
54981
  startIndex: match2.index,
54854
54982
  endIndex: match2.index + match2[0].length,
54855
- attributes
54983
+ attributes,
54984
+ isInJson: false
54856
54985
  });
54857
54986
  }
54858
54987
  return { diagrams, cleanedResponse: response };
54859
54988
  }
54989
+ function replaceMermaidDiagramsInJson(originalResponse, correctedDiagrams) {
54990
+ if (!originalResponse || typeof originalResponse !== "string") {
54991
+ return originalResponse;
54992
+ }
54993
+ if (!correctedDiagrams || correctedDiagrams.length === 0) {
54994
+ return originalResponse;
54995
+ }
54996
+ const jsonResult = extractMermaidFromJson(originalResponse);
54997
+ if (!jsonResult.parsedJson) {
54998
+ return originalResponse;
54999
+ }
55000
+ let modifiedJson = jsonResult.parsedJson;
55001
+ for (const diagram of correctedDiagrams) {
55002
+ if (!diagram.jsonPath || !diagram.isInJson) {
55003
+ continue;
55004
+ }
55005
+ const pathParts = diagram.jsonPath.split(".").filter((p) => p);
55006
+ let current = modifiedJson;
55007
+ for (let i = 0; i < pathParts.length - 1; i++) {
55008
+ const part = pathParts[i];
55009
+ if (part.startsWith("[") && part.endsWith("]")) {
55010
+ const index = parseInt(part.slice(1, -1), 10);
55011
+ current = current[index];
55012
+ } else {
55013
+ current = current[part];
55014
+ }
55015
+ }
55016
+ const lastPart = pathParts[pathParts.length - 1];
55017
+ const attributesStr = diagram.attributes ? ` ${diagram.attributes}` : "";
55018
+ const newCodeBlock = `\`\`\`mermaid${attributesStr}
55019
+ ${diagram.content}
55020
+ \`\`\``;
55021
+ if (lastPart.startsWith("[") && lastPart.endsWith("]")) {
55022
+ const index = parseInt(lastPart.slice(1, -1), 10);
55023
+ const originalString = current[index];
55024
+ current[index] = originalString.replace(diagram.fullMatch, newCodeBlock);
55025
+ } else {
55026
+ const originalString = current[lastPart];
55027
+ current[lastPart] = originalString.replace(diagram.fullMatch, newCodeBlock);
55028
+ }
55029
+ }
55030
+ const modifiedJsonString = JSON.stringify(modifiedJson, null, 2);
55031
+ const trimmed = originalResponse.trim();
55032
+ if (trimmed.match(/```json\s*\n([\s\S]*?)\n```/)) {
55033
+ return originalResponse.replace(/```json\s*\n([\s\S]*?)\n```/, `\`\`\`json
55034
+ ${modifiedJsonString}
55035
+ \`\`\``);
55036
+ } else if (trimmed.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/)) {
55037
+ return originalResponse.replace(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/, `\`\`\`
55038
+ ${modifiedJsonString}
55039
+ \`\`\``);
55040
+ }
55041
+ return modifiedJsonString;
55042
+ }
54860
55043
  function replaceMermaidDiagramsInMarkdown(originalResponse, correctedDiagrams) {
54861
55044
  if (!originalResponse || typeof originalResponse !== "string") {
54862
55045
  return originalResponse;
@@ -54864,6 +55047,10 @@ function replaceMermaidDiagramsInMarkdown(originalResponse, correctedDiagrams) {
54864
55047
  if (!correctedDiagrams || correctedDiagrams.length === 0) {
54865
55048
  return originalResponse;
54866
55049
  }
55050
+ const hasJsonDiagrams = correctedDiagrams.some((d) => d.isInJson);
55051
+ if (hasJsonDiagrams) {
55052
+ return replaceMermaidDiagramsInJson(originalResponse, correctedDiagrams);
55053
+ }
54867
55054
  let modifiedResponse = originalResponse;
54868
55055
  const sortedDiagrams = [...correctedDiagrams].sort((a, b) => b.startIndex - a.startIndex);
54869
55056
  for (const diagram of sortedDiagrams) {
@@ -57479,7 +57666,20 @@ var init_ProbeAgent = __esm({
57479
57666
  extract: wrappedTools.extractToolInstance,
57480
57667
  delegate: wrappedTools.delegateToolInstance,
57481
57668
  listFiles: listFilesToolInstance,
57482
- searchFiles: searchFilesToolInstance
57669
+ searchFiles: searchFilesToolInstance,
57670
+ readImage: {
57671
+ execute: async (params) => {
57672
+ const imagePath = params.path;
57673
+ if (!imagePath) {
57674
+ throw new Error("Image path is required");
57675
+ }
57676
+ const loaded = await this.loadImageIfValid(imagePath);
57677
+ if (!loaded) {
57678
+ 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.`);
57679
+ }
57680
+ return `Image loaded successfully: ${imagePath}. The image is now available for analysis in the conversation.`;
57681
+ }
57682
+ }
57483
57683
  };
57484
57684
  if (this.enableBash && wrappedTools.bashToolInstance) {
57485
57685
  this.toolImplementations.bash = wrappedTools.bashToolInstance;
@@ -58082,6 +58282,10 @@ var init_ProbeAgent = __esm({
58082
58282
  }
58083
58283
  if (isToolAllowed("searchFiles")) {
58084
58284
  toolDefinitions += `${searchFilesToolDefinition}
58285
+ `;
58286
+ }
58287
+ if (isToolAllowed("readImage")) {
58288
+ toolDefinitions += `${readImageToolDefinition}
58085
58289
  `;
58086
58290
  }
58087
58291
  if (this.allowEdit && isToolAllowed("implement")) {
@@ -58169,6 +58373,7 @@ Available Tools:
58169
58373
  - extract: Extract specific code blocks or lines from files.
58170
58374
  - listFiles: List files and directories in a specified location.
58171
58375
  - searchFiles: Find files matching a glob pattern with recursive search capability.
58376
+ - readImage: Read and load an image file for AI analysis.
58172
58377
  ${this.allowEdit ? "- implement: Implement a feature or fix a bug using aider.\n- edit: Edit files using exact string replacement.\n- create: Create new files with specified content.\n" : ""}${this.enableDelegate ? "- delegate: Delegate big distinct tasks to specialized probe subagents.\n" : ""}${this.enableBash ? "- bash: Execute bash commands for system operations.\n" : ""}
58173
58378
  - attempt_completion: Finalize the task and provide the result to the user.
58174
58379
  - attempt_complete: Quick completion using previous response (shorthand).
@@ -58526,24 +58731,21 @@ You are working with a repository located at: ${searchDirectory}
58526
58731
  const assistantPreview = createMessagePreview(assistantResponseContent);
58527
58732
  console.log(`[DEBUG] Assistant response (${assistantResponseContent.length} chars): ${assistantPreview}`);
58528
58733
  }
58529
- if (assistantResponseContent) {
58530
- await this.processImageReferences(assistantResponseContent);
58531
- }
58532
- const validTools = [
58533
- "search",
58534
- "query",
58535
- "extract",
58536
- "listFiles",
58537
- "searchFiles",
58538
- "attempt_completion"
58539
- ];
58540
- if (this.allowEdit) {
58734
+ const validTools = [];
58735
+ if (this.allowedTools.isEnabled("search")) validTools.push("search");
58736
+ if (this.allowedTools.isEnabled("query")) validTools.push("query");
58737
+ if (this.allowedTools.isEnabled("extract")) validTools.push("extract");
58738
+ if (this.allowedTools.isEnabled("listFiles")) validTools.push("listFiles");
58739
+ if (this.allowedTools.isEnabled("searchFiles")) validTools.push("searchFiles");
58740
+ if (this.allowedTools.isEnabled("readImage")) validTools.push("readImage");
58741
+ if (this.allowedTools.isEnabled("attempt_completion")) validTools.push("attempt_completion");
58742
+ if (this.allowEdit && this.allowedTools.isEnabled("implement")) {
58541
58743
  validTools.push("implement", "edit", "create");
58542
58744
  }
58543
- if (this.enableBash) {
58745
+ if (this.enableBash && this.allowedTools.isEnabled("bash")) {
58544
58746
  validTools.push("bash");
58545
58747
  }
58546
- if (this.enableDelegate) {
58748
+ if (this.enableDelegate && this.allowedTools.isEnabled("delegate")) {
58547
58749
  validTools.push("delegate");
58548
58750
  }
58549
58751
  const nativeTools = validTools;