@probelabs/probe 0.6.0-rc198 → 0.6.0-rc199

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.
@@ -7871,6 +7871,14 @@ var init_zod = __esm({
7871
7871
 
7872
7872
  // src/tools/common.js
7873
7873
  import { resolve, isAbsolute } from "path";
7874
+ function buildToolTagPattern(tools2 = DEFAULT_VALID_TOOLS) {
7875
+ const allTools = [...tools2];
7876
+ if (allTools.includes("attempt_completion") && !allTools.includes("attempt_complete")) {
7877
+ allTools.push("attempt_complete");
7878
+ }
7879
+ const escaped = allTools.map((t) => t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
7880
+ return new RegExp(`<(${escaped.join("|")})>`);
7881
+ }
7874
7882
  function getValidParamsForTool(toolName) {
7875
7883
  const schemaMap = {
7876
7884
  search: searchSchema,
@@ -8320,6 +8328,7 @@ User: Check system info
8320
8328
  "listFiles",
8321
8329
  "searchFiles",
8322
8330
  "implement",
8331
+ "bash",
8323
8332
  "attempt_completion"
8324
8333
  ];
8325
8334
  }
@@ -17708,7 +17717,7 @@ function removeThinkingTags(xmlString) {
17708
17717
  const thinkingIndex = result.indexOf("<thinking>");
17709
17718
  if (thinkingIndex !== -1) {
17710
17719
  const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
17711
- const toolPattern = /<(search|query|extract|listFiles|searchFiles|implement|attempt_completion|attempt_complete)>/;
17720
+ const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
17712
17721
  const toolMatch = afterThinking.match(toolPattern);
17713
17722
  if (toolMatch) {
17714
17723
  const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
@@ -17783,8 +17792,7 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
17783
17792
  return null;
17784
17793
  }
17785
17794
  function hasOtherToolTags(xmlString, validTools = []) {
17786
- const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
17787
- const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
17795
+ const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
17788
17796
  for (const tool4 of toolsToCheck) {
17789
17797
  if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
17790
17798
  return true;
@@ -17809,6 +17817,7 @@ ${thinkingContent}`);
17809
17817
  var init_xmlParsingUtils = __esm({
17810
17818
  "src/agent/xmlParsingUtils.js"() {
17811
17819
  "use strict";
17820
+ init_common();
17812
17821
  }
17813
17822
  });
17814
17823
 
@@ -3,6 +3,8 @@
3
3
  * This module contains the core logic for thinking tag removal and attempt_complete recovery
4
4
  */
5
5
 
6
+ import { DEFAULT_VALID_TOOLS, buildToolTagPattern } from '../tools/common.js';
7
+
6
8
  /**
7
9
  * Remove thinking tags and their content from XML string
8
10
  * Handles both closed and unclosed thinking tags
@@ -24,7 +26,8 @@ export function removeThinkingTags(xmlString) {
24
26
  const afterThinking = result.substring(thinkingIndex + '<thinking>'.length);
25
27
 
26
28
  // Look for any tool tags in the remaining content
27
- const toolPattern = /<(search|query|extract|listFiles|searchFiles|implement|attempt_completion|attempt_complete)>/;
29
+ // Use the shared tool list to build the pattern dynamically
30
+ const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
28
31
  const toolMatch = afterThinking.match(toolPattern);
29
32
 
30
33
  if (toolMatch) {
@@ -148,8 +151,8 @@ export function checkAttemptCompleteRecovery(cleanedXmlString, validTools = [])
148
151
  * @returns {boolean} - True if other tool tags are found
149
152
  */
150
153
  function hasOtherToolTags(xmlString, validTools = []) {
151
- const defaultTools = ['search', 'query', 'extract', 'listFiles', 'searchFiles', 'implement', 'attempt_completion'];
152
- const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
154
+ // Use the shared canonical tool list as default
155
+ const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
153
156
 
154
157
  // Check for any tool tags other than attempt_complete variants
155
158
  for (const tool of toolsToCheck) {
@@ -325,7 +325,8 @@ export const delegateDescription = 'Automatically delegate big distinct tasks to
325
325
  export const bashDescription = 'Execute bash commands for system exploration and development tasks. Secure by default with built-in allow/deny lists.';
326
326
 
327
327
  // Valid tool names that should be parsed as tool calls
328
- const DEFAULT_VALID_TOOLS = [
328
+ // This is the canonical list - all other tool lists should reference this
329
+ export const DEFAULT_VALID_TOOLS = [
329
330
  'search',
330
331
  'query',
331
332
  'extract',
@@ -333,9 +334,25 @@ const DEFAULT_VALID_TOOLS = [
333
334
  'listFiles',
334
335
  'searchFiles',
335
336
  'implement',
337
+ 'bash',
336
338
  'attempt_completion'
337
339
  ];
338
340
 
341
+ /**
342
+ * Build a regex pattern to match any tool tag from the valid tools list
343
+ * @param {string[]} tools - List of tool names (defaults to DEFAULT_VALID_TOOLS)
344
+ * @returns {RegExp} - Regex pattern to match tool opening tags
345
+ */
346
+ export function buildToolTagPattern(tools = DEFAULT_VALID_TOOLS) {
347
+ // Also include attempt_complete as an alias for attempt_completion
348
+ const allTools = [...tools];
349
+ if (allTools.includes('attempt_completion') && !allTools.includes('attempt_complete')) {
350
+ allTools.push('attempt_complete');
351
+ }
352
+ const escaped = allTools.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
353
+ return new RegExp(`<(${escaped.join('|')})>`);
354
+ }
355
+
339
356
  /**
340
357
  * Get valid parameter names for a specific tool from its schema
341
358
  * @param {string} toolName - Name of the tool
@@ -25,7 +25,9 @@ export {
25
25
  attemptCompletionSchema,
26
26
  attemptCompletionToolDefinition,
27
27
  parseAndResolvePaths,
28
- resolveTargetPath
28
+ resolveTargetPath,
29
+ DEFAULT_VALID_TOOLS,
30
+ buildToolTagPattern
29
31
  } from './common.js';
30
32
 
31
33
  // Export edit and create schemas
@@ -34822,6 +34822,14 @@ var init_zod = __esm({
34822
34822
  });
34823
34823
 
34824
34824
  // src/tools/common.js
34825
+ function buildToolTagPattern(tools2 = DEFAULT_VALID_TOOLS) {
34826
+ const allTools = [...tools2];
34827
+ if (allTools.includes("attempt_completion") && !allTools.includes("attempt_complete")) {
34828
+ allTools.push("attempt_complete");
34829
+ }
34830
+ const escaped = allTools.map((t4) => t4.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
34831
+ return new RegExp(`<(${escaped.join("|")})>`);
34832
+ }
34825
34833
  function getValidParamsForTool(toolName) {
34826
34834
  const schemaMap = {
34827
34835
  search: searchSchema,
@@ -35272,6 +35280,7 @@ User: Check system info
35272
35280
  "listFiles",
35273
35281
  "searchFiles",
35274
35282
  "implement",
35283
+ "bash",
35275
35284
  "attempt_completion"
35276
35285
  ];
35277
35286
  }
@@ -44436,7 +44445,7 @@ function removeThinkingTags(xmlString) {
44436
44445
  const thinkingIndex = result.indexOf("<thinking>");
44437
44446
  if (thinkingIndex !== -1) {
44438
44447
  const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
44439
- const toolPattern = /<(search|query|extract|listFiles|searchFiles|implement|attempt_completion|attempt_complete)>/;
44448
+ const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
44440
44449
  const toolMatch = afterThinking.match(toolPattern);
44441
44450
  if (toolMatch) {
44442
44451
  const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
@@ -44511,8 +44520,7 @@ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
44511
44520
  return null;
44512
44521
  }
44513
44522
  function hasOtherToolTags(xmlString, validTools = []) {
44514
- const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
44515
- const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
44523
+ const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
44516
44524
  for (const tool4 of toolsToCheck) {
44517
44525
  if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
44518
44526
  return true;
@@ -44537,6 +44545,7 @@ ${thinkingContent}`);
44537
44545
  var init_xmlParsingUtils = __esm({
44538
44546
  "src/agent/xmlParsingUtils.js"() {
44539
44547
  "use strict";
44548
+ init_common2();
44540
44549
  }
44541
44550
  });
44542
44551
 
package/cjs/index.cjs CHANGED
@@ -30515,261 +30515,6 @@ var init_imageConfig = __esm({
30515
30515
  }
30516
30516
  });
30517
30517
 
30518
- // src/agent/xmlParsingUtils.js
30519
- function removeThinkingTags(xmlString) {
30520
- let result = xmlString;
30521
- result = result.replace(/<thinking>[\s\S]*?<\/thinking>/g, "");
30522
- const thinkingIndex = result.indexOf("<thinking>");
30523
- if (thinkingIndex !== -1) {
30524
- const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
30525
- const toolPattern = /<(search|query|extract|listFiles|searchFiles|implement|attempt_completion|attempt_complete)>/;
30526
- const toolMatch = afterThinking.match(toolPattern);
30527
- if (toolMatch) {
30528
- const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
30529
- result = result.substring(0, thinkingIndex) + result.substring(toolStart);
30530
- } else {
30531
- result = result.substring(0, thinkingIndex);
30532
- }
30533
- }
30534
- return result.trim();
30535
- }
30536
- function extractThinkingContent(xmlString) {
30537
- const thinkingMatch = xmlString.match(/<thinking>([\s\S]*?)<\/thinking>/);
30538
- return thinkingMatch ? thinkingMatch[1].trim() : null;
30539
- }
30540
- function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
30541
- const openTagIndex = cleanedXmlString.indexOf("<attempt_completion>");
30542
- if (openTagIndex !== -1) {
30543
- const afterOpenTag = cleanedXmlString.substring(openTagIndex + "<attempt_completion>".length);
30544
- const closeTagIndex = cleanedXmlString.lastIndexOf("</attempt_completion>");
30545
- let content;
30546
- let hasClosingTag = false;
30547
- if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + "<attempt_completion>".length) {
30548
- content = cleanedXmlString.substring(
30549
- openTagIndex + "<attempt_completion>".length,
30550
- closeTagIndex
30551
- ).trim();
30552
- hasClosingTag = true;
30553
- } else {
30554
- content = afterOpenTag.trim();
30555
- hasClosingTag = false;
30556
- }
30557
- if (content) {
30558
- return {
30559
- toolName: "attempt_completion",
30560
- params: { result: content }
30561
- };
30562
- }
30563
- return {
30564
- toolName: "attempt_completion",
30565
- params: { result: hasClosingTag ? "" : "__PREVIOUS_RESPONSE__" }
30566
- };
30567
- }
30568
- const attemptCompletePatterns = [
30569
- // Standard shorthand with optional whitespace
30570
- /^<attempt_complete>\s*$/,
30571
- // Empty with proper closing tag (common case from the logs)
30572
- /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
30573
- // Self-closing variant
30574
- /^<attempt_complete\s*\/>\s*$/,
30575
- // Incomplete opening tag (missing closing bracket)
30576
- /^<attempt_complete\s*$/,
30577
- // With trailing content (extract just the tag part) - must come after empty tag pattern
30578
- /^<attempt_complete>(.*)$/s,
30579
- // Self-closing with trailing content
30580
- /^<attempt_complete\s*\/>(.*)$/s
30581
- ];
30582
- for (const pattern of attemptCompletePatterns) {
30583
- const match2 = cleanedXmlString.match(pattern);
30584
- if (match2) {
30585
- return {
30586
- toolName: "attempt_completion",
30587
- params: { result: "__PREVIOUS_RESPONSE__" }
30588
- };
30589
- }
30590
- }
30591
- if (cleanedXmlString.includes("<attempt_complete") && !hasOtherToolTags(cleanedXmlString, validTools)) {
30592
- return {
30593
- toolName: "attempt_completion",
30594
- params: { result: "__PREVIOUS_RESPONSE__" }
30595
- };
30596
- }
30597
- return null;
30598
- }
30599
- function hasOtherToolTags(xmlString, validTools = []) {
30600
- const defaultTools = ["search", "query", "extract", "listFiles", "searchFiles", "implement", "attempt_completion"];
30601
- const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
30602
- for (const tool4 of toolsToCheck) {
30603
- if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
30604
- return true;
30605
- }
30606
- }
30607
- return false;
30608
- }
30609
- function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
30610
- const thinkingContent = extractThinkingContent(xmlString);
30611
- const cleanedXmlString = removeThinkingTags(xmlString);
30612
- const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
30613
- if (process.env.DEBUG === "1" && thinkingContent) {
30614
- console.log(`[DEBUG] AI Thinking Process:
30615
- ${thinkingContent}`);
30616
- }
30617
- return {
30618
- cleanedXmlString,
30619
- thinkingContent,
30620
- recoveryResult
30621
- };
30622
- }
30623
- var init_xmlParsingUtils = __esm({
30624
- "src/agent/xmlParsingUtils.js"() {
30625
- "use strict";
30626
- }
30627
- });
30628
-
30629
- // src/agent/tools.js
30630
- function createTools(configOptions) {
30631
- const tools2 = {};
30632
- const isToolAllowed = configOptions.isToolAllowed || ((toolName) => {
30633
- if (!configOptions.allowedTools) return true;
30634
- return configOptions.allowedTools.isEnabled(toolName);
30635
- });
30636
- if (isToolAllowed("search")) {
30637
- tools2.searchTool = searchTool(configOptions);
30638
- }
30639
- if (isToolAllowed("query")) {
30640
- tools2.queryTool = queryTool(configOptions);
30641
- }
30642
- if (isToolAllowed("extract")) {
30643
- tools2.extractTool = extractTool(configOptions);
30644
- }
30645
- if (configOptions.enableDelegate && isToolAllowed("delegate")) {
30646
- tools2.delegateTool = delegateTool(configOptions);
30647
- }
30648
- if (configOptions.enableBash && isToolAllowed("bash")) {
30649
- tools2.bashTool = bashTool(configOptions);
30650
- }
30651
- if (configOptions.allowEdit && isToolAllowed("edit")) {
30652
- tools2.editTool = editTool(configOptions);
30653
- }
30654
- if (configOptions.allowEdit && isToolAllowed("create")) {
30655
- tools2.createTool = createTool(configOptions);
30656
- }
30657
- return tools2;
30658
- }
30659
- function parseXmlToolCallWithThinking(xmlString, validTools) {
30660
- const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
30661
- if (recoveryResult) {
30662
- return recoveryResult;
30663
- }
30664
- return parseXmlToolCall(cleanedXmlString, validTools);
30665
- }
30666
- var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, readImageToolDefinition;
30667
- var init_tools = __esm({
30668
- "src/agent/tools.js"() {
30669
- "use strict";
30670
- init_index();
30671
- import_crypto2 = require("crypto");
30672
- init_xmlParsingUtils();
30673
- implementToolDefinition = `
30674
- ## implement
30675
- Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
30676
-
30677
- Parameters:
30678
- - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
30679
- - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
30680
-
30681
- Usage Example:
30682
-
30683
- <examples>
30684
-
30685
- User: Can you implement a function to calculate Fibonacci numbers in main.js?
30686
- <implement>
30687
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
30688
- </implement>
30689
-
30690
- User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
30691
- <implement>
30692
- <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
30693
- <autoCommits>true</autoCommits>
30694
- </implement>
30695
-
30696
- </examples>
30697
- `;
30698
- listFilesToolDefinition = `
30699
- ## listFiles
30700
- Description: List files and directories in a specified location.
30701
-
30702
- Parameters:
30703
- - directory: (optional) The directory path to list files from. Defaults to current directory if not specified.
30704
-
30705
- Usage Example:
30706
-
30707
- <examples>
30708
-
30709
- User: Can you list the files in the src directory?
30710
- <listFiles>
30711
- <directory>src</directory>
30712
- </listFiles>
30713
-
30714
- User: What files are in the current directory?
30715
- <listFiles>
30716
- </listFiles>
30717
-
30718
- </examples>
30719
- `;
30720
- searchFilesToolDefinition = `
30721
- ## searchFiles
30722
- Description: Find files with name matching a glob pattern with recursive search capability.
30723
-
30724
- Parameters:
30725
- - pattern: (required) The glob pattern to search for (e.g., "**/*.js", "*.md").
30726
- - directory: (optional) The directory to search in. Defaults to current directory if not specified.
30727
- - recursive: (optional) Whether to search recursively. Defaults to true.
30728
-
30729
- Usage Example:
30730
-
30731
- <examples>
30732
-
30733
- User: Can you find all JavaScript files in the project?
30734
- <searchFiles>
30735
- <pattern>**/*.js</pattern>
30736
- </searchFiles>
30737
-
30738
- User: Find all markdown files in the docs directory, but only at the top level.
30739
- <searchFiles>
30740
- <pattern>*.md</pattern>
30741
- <directory>docs</directory>
30742
- <recursive>false</recursive>
30743
- </searchFiles>
30744
-
30745
- </examples>
30746
- `;
30747
- readImageToolDefinition = `
30748
- ## readImage
30749
- 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.
30750
-
30751
- Parameters:
30752
- - path: (required) The path to the image file to read. Supports png, jpg, jpeg, webp, bmp, and svg formats.
30753
-
30754
- Usage Example:
30755
-
30756
- <examples>
30757
-
30758
- User: Can you describe what's in screenshot.png?
30759
- <readImage>
30760
- <path>screenshot.png</path>
30761
- </readImage>
30762
-
30763
- User: Analyze the diagram in docs/architecture.svg
30764
- <readImage>
30765
- <path>docs/architecture.svg</path>
30766
- </readImage>
30767
-
30768
- </examples>
30769
- `;
30770
- }
30771
- });
30772
-
30773
30518
  // node_modules/zod/v3/helpers/util.js
30774
30519
  var util, objectUtil, ZodParsedType, getParsedType;
30775
30520
  var init_util2 = __esm({
@@ -34877,6 +34622,14 @@ var init_zod = __esm({
34877
34622
  });
34878
34623
 
34879
34624
  // src/tools/common.js
34625
+ function buildToolTagPattern(tools2 = DEFAULT_VALID_TOOLS) {
34626
+ const allTools = [...tools2];
34627
+ if (allTools.includes("attempt_completion") && !allTools.includes("attempt_complete")) {
34628
+ allTools.push("attempt_complete");
34629
+ }
34630
+ const escaped = allTools.map((t4) => t4.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
34631
+ return new RegExp(`<(${escaped.join("|")})>`);
34632
+ }
34880
34633
  function getValidParamsForTool(toolName) {
34881
34634
  const schemaMap = {
34882
34635
  search: searchSchema,
@@ -35328,11 +35081,267 @@ User: Check system info
35328
35081
  "listFiles",
35329
35082
  "searchFiles",
35330
35083
  "implement",
35084
+ "bash",
35331
35085
  "attempt_completion"
35332
35086
  ];
35333
35087
  }
35334
35088
  });
35335
35089
 
35090
+ // src/agent/xmlParsingUtils.js
35091
+ function removeThinkingTags(xmlString) {
35092
+ let result = xmlString;
35093
+ result = result.replace(/<thinking>[\s\S]*?<\/thinking>/g, "");
35094
+ const thinkingIndex = result.indexOf("<thinking>");
35095
+ if (thinkingIndex !== -1) {
35096
+ const afterThinking = result.substring(thinkingIndex + "<thinking>".length);
35097
+ const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
35098
+ const toolMatch = afterThinking.match(toolPattern);
35099
+ if (toolMatch) {
35100
+ const toolStart = thinkingIndex + "<thinking>".length + toolMatch.index;
35101
+ result = result.substring(0, thinkingIndex) + result.substring(toolStart);
35102
+ } else {
35103
+ result = result.substring(0, thinkingIndex);
35104
+ }
35105
+ }
35106
+ return result.trim();
35107
+ }
35108
+ function extractThinkingContent(xmlString) {
35109
+ const thinkingMatch = xmlString.match(/<thinking>([\s\S]*?)<\/thinking>/);
35110
+ return thinkingMatch ? thinkingMatch[1].trim() : null;
35111
+ }
35112
+ function checkAttemptCompleteRecovery(cleanedXmlString, validTools = []) {
35113
+ const openTagIndex = cleanedXmlString.indexOf("<attempt_completion>");
35114
+ if (openTagIndex !== -1) {
35115
+ const afterOpenTag = cleanedXmlString.substring(openTagIndex + "<attempt_completion>".length);
35116
+ const closeTagIndex = cleanedXmlString.lastIndexOf("</attempt_completion>");
35117
+ let content;
35118
+ let hasClosingTag = false;
35119
+ if (closeTagIndex !== -1 && closeTagIndex >= openTagIndex + "<attempt_completion>".length) {
35120
+ content = cleanedXmlString.substring(
35121
+ openTagIndex + "<attempt_completion>".length,
35122
+ closeTagIndex
35123
+ ).trim();
35124
+ hasClosingTag = true;
35125
+ } else {
35126
+ content = afterOpenTag.trim();
35127
+ hasClosingTag = false;
35128
+ }
35129
+ if (content) {
35130
+ return {
35131
+ toolName: "attempt_completion",
35132
+ params: { result: content }
35133
+ };
35134
+ }
35135
+ return {
35136
+ toolName: "attempt_completion",
35137
+ params: { result: hasClosingTag ? "" : "__PREVIOUS_RESPONSE__" }
35138
+ };
35139
+ }
35140
+ const attemptCompletePatterns = [
35141
+ // Standard shorthand with optional whitespace
35142
+ /^<attempt_complete>\s*$/,
35143
+ // Empty with proper closing tag (common case from the logs)
35144
+ /^<attempt_complete>\s*<\/attempt_complete>\s*$/,
35145
+ // Self-closing variant
35146
+ /^<attempt_complete\s*\/>\s*$/,
35147
+ // Incomplete opening tag (missing closing bracket)
35148
+ /^<attempt_complete\s*$/,
35149
+ // With trailing content (extract just the tag part) - must come after empty tag pattern
35150
+ /^<attempt_complete>(.*)$/s,
35151
+ // Self-closing with trailing content
35152
+ /^<attempt_complete\s*\/>(.*)$/s
35153
+ ];
35154
+ for (const pattern of attemptCompletePatterns) {
35155
+ const match2 = cleanedXmlString.match(pattern);
35156
+ if (match2) {
35157
+ return {
35158
+ toolName: "attempt_completion",
35159
+ params: { result: "__PREVIOUS_RESPONSE__" }
35160
+ };
35161
+ }
35162
+ }
35163
+ if (cleanedXmlString.includes("<attempt_complete") && !hasOtherToolTags(cleanedXmlString, validTools)) {
35164
+ return {
35165
+ toolName: "attempt_completion",
35166
+ params: { result: "__PREVIOUS_RESPONSE__" }
35167
+ };
35168
+ }
35169
+ return null;
35170
+ }
35171
+ function hasOtherToolTags(xmlString, validTools = []) {
35172
+ const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
35173
+ for (const tool4 of toolsToCheck) {
35174
+ if (tool4 !== "attempt_completion" && xmlString.includes(`<${tool4}`)) {
35175
+ return true;
35176
+ }
35177
+ }
35178
+ return false;
35179
+ }
35180
+ function processXmlWithThinkingAndRecovery(xmlString, validTools = []) {
35181
+ const thinkingContent = extractThinkingContent(xmlString);
35182
+ const cleanedXmlString = removeThinkingTags(xmlString);
35183
+ const recoveryResult = checkAttemptCompleteRecovery(cleanedXmlString, validTools);
35184
+ if (process.env.DEBUG === "1" && thinkingContent) {
35185
+ console.log(`[DEBUG] AI Thinking Process:
35186
+ ${thinkingContent}`);
35187
+ }
35188
+ return {
35189
+ cleanedXmlString,
35190
+ thinkingContent,
35191
+ recoveryResult
35192
+ };
35193
+ }
35194
+ var init_xmlParsingUtils = __esm({
35195
+ "src/agent/xmlParsingUtils.js"() {
35196
+ "use strict";
35197
+ init_common2();
35198
+ }
35199
+ });
35200
+
35201
+ // src/agent/tools.js
35202
+ function createTools(configOptions) {
35203
+ const tools2 = {};
35204
+ const isToolAllowed = configOptions.isToolAllowed || ((toolName) => {
35205
+ if (!configOptions.allowedTools) return true;
35206
+ return configOptions.allowedTools.isEnabled(toolName);
35207
+ });
35208
+ if (isToolAllowed("search")) {
35209
+ tools2.searchTool = searchTool(configOptions);
35210
+ }
35211
+ if (isToolAllowed("query")) {
35212
+ tools2.queryTool = queryTool(configOptions);
35213
+ }
35214
+ if (isToolAllowed("extract")) {
35215
+ tools2.extractTool = extractTool(configOptions);
35216
+ }
35217
+ if (configOptions.enableDelegate && isToolAllowed("delegate")) {
35218
+ tools2.delegateTool = delegateTool(configOptions);
35219
+ }
35220
+ if (configOptions.enableBash && isToolAllowed("bash")) {
35221
+ tools2.bashTool = bashTool(configOptions);
35222
+ }
35223
+ if (configOptions.allowEdit && isToolAllowed("edit")) {
35224
+ tools2.editTool = editTool(configOptions);
35225
+ }
35226
+ if (configOptions.allowEdit && isToolAllowed("create")) {
35227
+ tools2.createTool = createTool(configOptions);
35228
+ }
35229
+ return tools2;
35230
+ }
35231
+ function parseXmlToolCallWithThinking(xmlString, validTools) {
35232
+ const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
35233
+ if (recoveryResult) {
35234
+ return recoveryResult;
35235
+ }
35236
+ return parseXmlToolCall(cleanedXmlString, validTools);
35237
+ }
35238
+ var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, readImageToolDefinition;
35239
+ var init_tools = __esm({
35240
+ "src/agent/tools.js"() {
35241
+ "use strict";
35242
+ init_index();
35243
+ import_crypto2 = require("crypto");
35244
+ init_xmlParsingUtils();
35245
+ implementToolDefinition = `
35246
+ ## implement
35247
+ Description: Implement a given task. Can modify files. Can be used ONLY if task explicitly stated that something requires modification or implementation.
35248
+
35249
+ Parameters:
35250
+ - task: (required) The task description. Should be as detailed as possible, ideally pointing to exact files which needs be modified or created.
35251
+ - autoCommits: (optional) Whether to enable auto-commits in aider. Default is false.
35252
+
35253
+ Usage Example:
35254
+
35255
+ <examples>
35256
+
35257
+ User: Can you implement a function to calculate Fibonacci numbers in main.js?
35258
+ <implement>
35259
+ <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
35260
+ </implement>
35261
+
35262
+ User: Can you implement a function to calculate Fibonacci numbers in main.js with auto-commits?
35263
+ <implement>
35264
+ <task>Implement a recursive function to calculate the nth Fibonacci number in main.js</task>
35265
+ <autoCommits>true</autoCommits>
35266
+ </implement>
35267
+
35268
+ </examples>
35269
+ `;
35270
+ listFilesToolDefinition = `
35271
+ ## listFiles
35272
+ Description: List files and directories in a specified location.
35273
+
35274
+ Parameters:
35275
+ - directory: (optional) The directory path to list files from. Defaults to current directory if not specified.
35276
+
35277
+ Usage Example:
35278
+
35279
+ <examples>
35280
+
35281
+ User: Can you list the files in the src directory?
35282
+ <listFiles>
35283
+ <directory>src</directory>
35284
+ </listFiles>
35285
+
35286
+ User: What files are in the current directory?
35287
+ <listFiles>
35288
+ </listFiles>
35289
+
35290
+ </examples>
35291
+ `;
35292
+ searchFilesToolDefinition = `
35293
+ ## searchFiles
35294
+ Description: Find files with name matching a glob pattern with recursive search capability.
35295
+
35296
+ Parameters:
35297
+ - pattern: (required) The glob pattern to search for (e.g., "**/*.js", "*.md").
35298
+ - directory: (optional) The directory to search in. Defaults to current directory if not specified.
35299
+ - recursive: (optional) Whether to search recursively. Defaults to true.
35300
+
35301
+ Usage Example:
35302
+
35303
+ <examples>
35304
+
35305
+ User: Can you find all JavaScript files in the project?
35306
+ <searchFiles>
35307
+ <pattern>**/*.js</pattern>
35308
+ </searchFiles>
35309
+
35310
+ User: Find all markdown files in the docs directory, but only at the top level.
35311
+ <searchFiles>
35312
+ <pattern>*.md</pattern>
35313
+ <directory>docs</directory>
35314
+ <recursive>false</recursive>
35315
+ </searchFiles>
35316
+
35317
+ </examples>
35318
+ `;
35319
+ readImageToolDefinition = `
35320
+ ## readImage
35321
+ 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.
35322
+
35323
+ Parameters:
35324
+ - path: (required) The path to the image file to read. Supports png, jpg, jpeg, webp, bmp, and svg formats.
35325
+
35326
+ Usage Example:
35327
+
35328
+ <examples>
35329
+
35330
+ User: Can you describe what's in screenshot.png?
35331
+ <readImage>
35332
+ <path>screenshot.png</path>
35333
+ </readImage>
35334
+
35335
+ User: Analyze the diagram in docs/architecture.svg
35336
+ <readImage>
35337
+ <path>docs/architecture.svg</path>
35338
+ </readImage>
35339
+
35340
+ </examples>
35341
+ `;
35342
+ }
35343
+ });
35344
+
35336
35345
  // node_modules/balanced-match/index.js
35337
35346
  var require_balanced_match = __commonJS({
35338
35347
  "node_modules/balanced-match/index.js"(exports2, module2) {
@@ -88796,12 +88805,14 @@ For GitHub-compatible mermaid diagrams, avoid single quotes and parentheses in n
88796
88805
  var tools_exports = {};
88797
88806
  __export(tools_exports, {
88798
88807
  DEFAULT_SYSTEM_MESSAGE: () => DEFAULT_SYSTEM_MESSAGE,
88808
+ DEFAULT_VALID_TOOLS: () => DEFAULT_VALID_TOOLS,
88799
88809
  attemptCompletionSchema: () => attemptCompletionSchema,
88800
88810
  attemptCompletionToolDefinition: () => attemptCompletionToolDefinition,
88801
88811
  bashDescription: () => bashDescription,
88802
88812
  bashSchema: () => bashSchema,
88803
88813
  bashTool: () => bashTool,
88804
88814
  bashToolDefinition: () => bashToolDefinition,
88815
+ buildToolTagPattern: () => buildToolTagPattern,
88805
88816
  createDescription: () => createDescription,
88806
88817
  createExtractTool: () => createExtractTool,
88807
88818
  createQueryTool: () => createQueryTool,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc198",
3
+ "version": "0.6.0-rc199",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
@@ -3,6 +3,8 @@
3
3
  * This module contains the core logic for thinking tag removal and attempt_complete recovery
4
4
  */
5
5
 
6
+ import { DEFAULT_VALID_TOOLS, buildToolTagPattern } from '../tools/common.js';
7
+
6
8
  /**
7
9
  * Remove thinking tags and their content from XML string
8
10
  * Handles both closed and unclosed thinking tags
@@ -24,7 +26,8 @@ export function removeThinkingTags(xmlString) {
24
26
  const afterThinking = result.substring(thinkingIndex + '<thinking>'.length);
25
27
 
26
28
  // Look for any tool tags in the remaining content
27
- const toolPattern = /<(search|query|extract|listFiles|searchFiles|implement|attempt_completion|attempt_complete)>/;
29
+ // Use the shared tool list to build the pattern dynamically
30
+ const toolPattern = buildToolTagPattern(DEFAULT_VALID_TOOLS);
28
31
  const toolMatch = afterThinking.match(toolPattern);
29
32
 
30
33
  if (toolMatch) {
@@ -148,8 +151,8 @@ export function checkAttemptCompleteRecovery(cleanedXmlString, validTools = [])
148
151
  * @returns {boolean} - True if other tool tags are found
149
152
  */
150
153
  function hasOtherToolTags(xmlString, validTools = []) {
151
- const defaultTools = ['search', 'query', 'extract', 'listFiles', 'searchFiles', 'implement', 'attempt_completion'];
152
- const toolsToCheck = validTools.length > 0 ? validTools : defaultTools;
154
+ // Use the shared canonical tool list as default
155
+ const toolsToCheck = validTools.length > 0 ? validTools : DEFAULT_VALID_TOOLS;
153
156
 
154
157
  // Check for any tool tags other than attempt_complete variants
155
158
  for (const tool of toolsToCheck) {
@@ -325,7 +325,8 @@ export const delegateDescription = 'Automatically delegate big distinct tasks to
325
325
  export const bashDescription = 'Execute bash commands for system exploration and development tasks. Secure by default with built-in allow/deny lists.';
326
326
 
327
327
  // Valid tool names that should be parsed as tool calls
328
- const DEFAULT_VALID_TOOLS = [
328
+ // This is the canonical list - all other tool lists should reference this
329
+ export const DEFAULT_VALID_TOOLS = [
329
330
  'search',
330
331
  'query',
331
332
  'extract',
@@ -333,9 +334,25 @@ const DEFAULT_VALID_TOOLS = [
333
334
  'listFiles',
334
335
  'searchFiles',
335
336
  'implement',
337
+ 'bash',
336
338
  'attempt_completion'
337
339
  ];
338
340
 
341
+ /**
342
+ * Build a regex pattern to match any tool tag from the valid tools list
343
+ * @param {string[]} tools - List of tool names (defaults to DEFAULT_VALID_TOOLS)
344
+ * @returns {RegExp} - Regex pattern to match tool opening tags
345
+ */
346
+ export function buildToolTagPattern(tools = DEFAULT_VALID_TOOLS) {
347
+ // Also include attempt_complete as an alias for attempt_completion
348
+ const allTools = [...tools];
349
+ if (allTools.includes('attempt_completion') && !allTools.includes('attempt_complete')) {
350
+ allTools.push('attempt_complete');
351
+ }
352
+ const escaped = allTools.map(t => t.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
353
+ return new RegExp(`<(${escaped.join('|')})>`);
354
+ }
355
+
339
356
  /**
340
357
  * Get valid parameter names for a specific tool from its schema
341
358
  * @param {string} toolName - Name of the tool
@@ -25,7 +25,9 @@ export {
25
25
  attemptCompletionSchema,
26
26
  attemptCompletionToolDefinition,
27
27
  parseAndResolvePaths,
28
- resolveTargetPath
28
+ resolveTargetPath,
29
+ DEFAULT_VALID_TOOLS,
30
+ buildToolTagPattern
29
31
  } from './common.js';
30
32
 
31
33
  // Export edit and create schemas