@probelabs/probe 0.6.0-rc163 → 0.6.0-rc165

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.
@@ -1706,16 +1706,25 @@ When troubleshooting:
1706
1706
  }
1707
1707
 
1708
1708
  // 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) {
1709
+ // Build validTools based on allowedTools configuration (same pattern as getSystemMessage)
1710
+ const validTools = [];
1711
+ if (this.allowedTools.isEnabled('search')) validTools.push('search');
1712
+ if (this.allowedTools.isEnabled('query')) validTools.push('query');
1713
+ if (this.allowedTools.isEnabled('extract')) validTools.push('extract');
1714
+ if (this.allowedTools.isEnabled('listFiles')) validTools.push('listFiles');
1715
+ if (this.allowedTools.isEnabled('searchFiles')) validTools.push('searchFiles');
1716
+ if (this.allowedTools.isEnabled('attempt_completion')) validTools.push('attempt_completion');
1717
+
1718
+ // Edit tools (require both allowEdit flag AND allowedTools permission)
1719
+ if (this.allowEdit && this.allowedTools.isEnabled('implement')) {
1713
1720
  validTools.push('implement', 'edit', 'create');
1714
1721
  }
1715
- if (this.enableBash) {
1722
+ // Bash tool (require both enableBash flag AND allowedTools permission)
1723
+ if (this.enableBash && this.allowedTools.isEnabled('bash')) {
1716
1724
  validTools.push('bash');
1717
1725
  }
1718
- if (this.enableDelegate) {
1726
+ // Delegate tool (require both enableDelegate flag AND allowedTools permission)
1727
+ if (this.enableDelegate && this.allowedTools.isEnabled('delegate')) {
1719
1728
  validTools.push('delegate');
1720
1729
  }
1721
1730
 
@@ -2009,21 +2018,8 @@ When troubleshooting:
2009
2018
  // Add assistant response and ask for tool usage
2010
2019
  currentMessages.push({ role: 'assistant', content: assistantResponseContent });
2011
2020
 
2012
- // Build appropriate reminder message based on whether schema is provided
2013
- let reminderContent;
2014
- if (options.schema) { // Apply for ANY schema, not just JSON schemas
2015
- // When schema is provided, use the same instructions as initial message
2016
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2017
-
2018
- Remember: Use proper XML format with BOTH opening and closing tags:
2019
-
2020
- <tool_name>
2021
- <parameter>value</parameter>
2022
- </tool_name>
2023
- ` + generateSchemaInstructions(options.schema, { debug: this.debug }).trim();
2024
- } else {
2025
- // Standard reminder without schema
2026
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2021
+ // Standard reminder - schema was already provided in initial message
2022
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
2027
2023
 
2028
2024
  Remember: Use proper XML format with BOTH opening and closing tags:
2029
2025
 
@@ -2035,7 +2031,6 @@ Or for quick completion if your previous response was already correct and comple
2035
2031
  <attempt_complete>
2036
2032
 
2037
2033
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
2038
- }
2039
2034
 
2040
2035
  currentMessages.push({
2041
2036
  role: 'user',
@@ -54263,6 +54263,7 @@ __export(schemaUtils_exports, {
54263
54263
  createMermaidCorrectionPrompt: () => createMermaidCorrectionPrompt,
54264
54264
  createSchemaDefinitionCorrectionPrompt: () => createSchemaDefinitionCorrectionPrompt,
54265
54265
  decodeHtmlEntities: () => decodeHtmlEntities,
54266
+ extractMermaidFromJson: () => extractMermaidFromJson,
54266
54267
  extractMermaidFromMarkdown: () => extractMermaidFromMarkdown,
54267
54268
  generateExampleFromSchema: () => generateExampleFromSchema,
54268
54269
  generateSchemaInstructions: () => generateSchemaInstructions,
@@ -54270,6 +54271,7 @@ __export(schemaUtils_exports, {
54270
54271
  isJsonSchemaDefinition: () => isJsonSchemaDefinition,
54271
54272
  isMermaidSchema: () => isMermaidSchema,
54272
54273
  processSchemaResponse: () => processSchemaResponse,
54274
+ replaceMermaidDiagramsInJson: () => replaceMermaidDiagramsInJson,
54273
54275
  replaceMermaidDiagramsInMarkdown: () => replaceMermaidDiagramsInMarkdown,
54274
54276
  tryMaidAutoFix: () => tryMaidAutoFix,
54275
54277
  validateAndFixMermaidResponse: () => validateAndFixMermaidResponse,
@@ -54315,15 +54317,6 @@ function generateSchemaInstructions(schema, options = {}) {
54315
54317
  instructions += `${JSON.stringify(parsedSchema, null, 2)}
54316
54318
 
54317
54319
  `;
54318
- const exampleObj = generateExampleFromSchema(parsedSchema, { debug });
54319
- if (exampleObj) {
54320
- instructions += `Example:
54321
- <attempt_completion>
54322
- ${JSON.stringify(exampleObj, null, 2)}
54323
- </attempt_completion>
54324
-
54325
- `;
54326
- }
54327
54320
  } catch (e) {
54328
54321
  if (debug) {
54329
54322
  console.error("[DEBUG] generateSchemaInstructions: Failed to parse schema:", e.message);
@@ -54332,7 +54325,7 @@ ${JSON.stringify(exampleObj, null, 2)}
54332
54325
 
54333
54326
  `;
54334
54327
  }
54335
- instructions += "Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.";
54328
+ instructions += "Your response inside attempt_completion must be ONLY valid JSON - no plain text, no explanations, no markdown.\n\nIMPORTANT: First complete the requested analysis/task thoroughly, then provide your final answer in the JSON format above.";
54336
54329
  return instructions;
54337
54330
  }
54338
54331
  function enforceNoAdditionalProperties(schema) {
@@ -54382,6 +54375,49 @@ function decodeHtmlEntities(text) {
54382
54375
  }
54383
54376
  return decoded;
54384
54377
  }
54378
+ function normalizeJsonQuotes(str) {
54379
+ if (!str || typeof str !== "string") {
54380
+ return str;
54381
+ }
54382
+ if (!str.includes("'")) {
54383
+ return str;
54384
+ }
54385
+ let result = "";
54386
+ let inDoubleQuote = false;
54387
+ let inSingleQuote = false;
54388
+ let escaped = false;
54389
+ for (let i = 0; i < str.length; i++) {
54390
+ const char = str[i];
54391
+ const prevChar = i > 0 ? str[i - 1] : "";
54392
+ if (escaped) {
54393
+ result += char;
54394
+ escaped = false;
54395
+ continue;
54396
+ }
54397
+ if (char === "\\") {
54398
+ escaped = true;
54399
+ result += char;
54400
+ continue;
54401
+ }
54402
+ if (char === '"' && !inSingleQuote) {
54403
+ inDoubleQuote = !inDoubleQuote;
54404
+ result += char;
54405
+ continue;
54406
+ }
54407
+ if (char === "'" && !inDoubleQuote) {
54408
+ if (inSingleQuote) {
54409
+ result += '"';
54410
+ inSingleQuote = false;
54411
+ } else {
54412
+ result += '"';
54413
+ inSingleQuote = true;
54414
+ }
54415
+ continue;
54416
+ }
54417
+ result += char;
54418
+ }
54419
+ return result;
54420
+ }
54385
54421
  function cleanSchemaResponse(response) {
54386
54422
  if (!response || typeof response !== "string") {
54387
54423
  return response;
@@ -54389,23 +54425,27 @@ function cleanSchemaResponse(response) {
54389
54425
  const trimmed = response.trim();
54390
54426
  const jsonBlockMatch = trimmed.match(/```json\s*\n([\s\S]*?)\n```/);
54391
54427
  if (jsonBlockMatch) {
54392
- return jsonBlockMatch[1].trim();
54428
+ return normalizeJsonQuotes(jsonBlockMatch[1].trim());
54393
54429
  }
54394
54430
  const anyBlockMatch = trimmed.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/);
54395
54431
  if (anyBlockMatch) {
54396
- return anyBlockMatch[1].trim();
54432
+ return normalizeJsonQuotes(anyBlockMatch[1].trim());
54397
54433
  }
54398
54434
  const codeBlockPatterns = [
54399
54435
  /```json\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
54400
- /```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/,
54401
- /`([{\[][\s\S]*?[}\]])`/
54436
+ /```\s*\n?([{\[][\s\S]*?[}\]])\s*\n?```/
54402
54437
  ];
54403
54438
  for (const pattern of codeBlockPatterns) {
54404
54439
  const match2 = trimmed.match(pattern);
54405
54440
  if (match2) {
54406
- return match2[1].trim();
54441
+ return normalizeJsonQuotes(match2[1].trim());
54407
54442
  }
54408
54443
  }
54444
+ const singleBacktickPattern = /^`([{\[][\s\S]*?[}\]])`$/;
54445
+ const singleBacktickMatch = trimmed.match(singleBacktickPattern);
54446
+ if (singleBacktickMatch) {
54447
+ return normalizeJsonQuotes(singleBacktickMatch[1].trim());
54448
+ }
54409
54449
  const codeBlockStartPattern = /```(?:json)?\s*\n?\s*([{\[])/;
54410
54450
  const codeBlockMatch = trimmed.match(codeBlockStartPattern);
54411
54451
  if (codeBlockMatch) {
@@ -54424,7 +54464,7 @@ function cleanSchemaResponse(response) {
54424
54464
  endIndex++;
54425
54465
  }
54426
54466
  if (bracketCount === 0) {
54427
- return trimmed.substring(startIndex, endIndex);
54467
+ return normalizeJsonQuotes(trimmed.substring(startIndex, endIndex));
54428
54468
  }
54429
54469
  }
54430
54470
  let cleaned = trimmed;
@@ -54436,7 +54476,7 @@ function cleanSchemaResponse(response) {
54436
54476
  const isJsonObject = firstChar === "{" && lastChar === "}";
54437
54477
  const isJsonArray = firstChar === "[" && lastChar === "]";
54438
54478
  if (isJsonObject || isJsonArray) {
54439
- return cleaned;
54479
+ return normalizeJsonQuotes(cleaned);
54440
54480
  }
54441
54481
  return response;
54442
54482
  }
@@ -54846,10 +54886,66 @@ function isMermaidSchema(schema) {
54846
54886
  ];
54847
54887
  return mermaidIndicators.some((indicator) => indicator);
54848
54888
  }
54889
+ function extractMermaidFromJson(response) {
54890
+ if (!response || typeof response !== "string") {
54891
+ return { diagrams: [], jsonPaths: [], parsedJson: null };
54892
+ }
54893
+ let jsonContent = response.trim();
54894
+ const jsonBlockMatch = jsonContent.match(/```json\s*\n([\s\S]*?)\n```/);
54895
+ if (jsonBlockMatch) {
54896
+ jsonContent = jsonBlockMatch[1].trim();
54897
+ } else {
54898
+ const anyBlockMatch = jsonContent.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/);
54899
+ if (anyBlockMatch) {
54900
+ jsonContent = anyBlockMatch[1].trim();
54901
+ }
54902
+ }
54903
+ let parsedJson;
54904
+ try {
54905
+ parsedJson = JSON.parse(jsonContent);
54906
+ } catch (e) {
54907
+ return { diagrams: [], jsonPaths: [], parsedJson: null };
54908
+ }
54909
+ const diagrams = [];
54910
+ const jsonPaths = [];
54911
+ function searchObject(obj, path7 = []) {
54912
+ if (typeof obj === "string") {
54913
+ const mermaidPattern = /```mermaid([^\n`]*?)(?:\n|\\n)([\s\S]*?)```/gi;
54914
+ let match2;
54915
+ while ((match2 = mermaidPattern.exec(obj)) !== null) {
54916
+ const attributes = match2[1] ? match2[1].trim() : "";
54917
+ const content = match2[2].replace(/\\n/g, "\n");
54918
+ diagrams.push({
54919
+ content,
54920
+ fullMatch: match2[0],
54921
+ startIndex: match2.index,
54922
+ endIndex: match2.index + match2[0].length,
54923
+ attributes,
54924
+ isInJson: true,
54925
+ jsonPath: path7.join(".")
54926
+ });
54927
+ jsonPaths.push(path7.join("."));
54928
+ }
54929
+ } else if (Array.isArray(obj)) {
54930
+ obj.forEach((item, index) => searchObject(item, [...path7, `[${index}]`]));
54931
+ } else if (obj && typeof obj === "object") {
54932
+ Object.entries(obj).forEach(([key, value]) => searchObject(value, [...path7, key]));
54933
+ }
54934
+ }
54935
+ searchObject(parsedJson);
54936
+ return { diagrams, jsonPaths, parsedJson };
54937
+ }
54849
54938
  function extractMermaidFromMarkdown(response) {
54850
54939
  if (!response || typeof response !== "string") {
54851
54940
  return { diagrams: [], cleanedResponse: response };
54852
54941
  }
54942
+ const trimmed = response.trim();
54943
+ if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.includes("```json")) {
54944
+ const jsonResult = extractMermaidFromJson(response);
54945
+ if (jsonResult.diagrams.length > 0) {
54946
+ return { diagrams: jsonResult.diagrams, cleanedResponse: response };
54947
+ }
54948
+ }
54853
54949
  const mermaidBlockRegex = /```mermaid([^\n]*)\n([\s\S]*?)```/gi;
54854
54950
  const diagrams = [];
54855
54951
  let match2;
@@ -54861,11 +54957,66 @@ function extractMermaidFromMarkdown(response) {
54861
54957
  fullMatch: match2[0],
54862
54958
  startIndex: match2.index,
54863
54959
  endIndex: match2.index + match2[0].length,
54864
- attributes
54960
+ attributes,
54961
+ isInJson: false
54865
54962
  });
54866
54963
  }
54867
54964
  return { diagrams, cleanedResponse: response };
54868
54965
  }
54966
+ function replaceMermaidDiagramsInJson(originalResponse, correctedDiagrams) {
54967
+ if (!originalResponse || typeof originalResponse !== "string") {
54968
+ return originalResponse;
54969
+ }
54970
+ if (!correctedDiagrams || correctedDiagrams.length === 0) {
54971
+ return originalResponse;
54972
+ }
54973
+ const jsonResult = extractMermaidFromJson(originalResponse);
54974
+ if (!jsonResult.parsedJson) {
54975
+ return originalResponse;
54976
+ }
54977
+ let modifiedJson = jsonResult.parsedJson;
54978
+ for (const diagram of correctedDiagrams) {
54979
+ if (!diagram.jsonPath || !diagram.isInJson) {
54980
+ continue;
54981
+ }
54982
+ const pathParts = diagram.jsonPath.split(".").filter((p) => p);
54983
+ let current = modifiedJson;
54984
+ for (let i = 0; i < pathParts.length - 1; i++) {
54985
+ const part = pathParts[i];
54986
+ if (part.startsWith("[") && part.endsWith("]")) {
54987
+ const index = parseInt(part.slice(1, -1), 10);
54988
+ current = current[index];
54989
+ } else {
54990
+ current = current[part];
54991
+ }
54992
+ }
54993
+ const lastPart = pathParts[pathParts.length - 1];
54994
+ const attributesStr = diagram.attributes ? ` ${diagram.attributes}` : "";
54995
+ const newCodeBlock = `\`\`\`mermaid${attributesStr}
54996
+ ${diagram.content}
54997
+ \`\`\``;
54998
+ if (lastPart.startsWith("[") && lastPart.endsWith("]")) {
54999
+ const index = parseInt(lastPart.slice(1, -1), 10);
55000
+ const originalString = current[index];
55001
+ current[index] = originalString.replace(diagram.fullMatch, newCodeBlock);
55002
+ } else {
55003
+ const originalString = current[lastPart];
55004
+ current[lastPart] = originalString.replace(diagram.fullMatch, newCodeBlock);
55005
+ }
55006
+ }
55007
+ const modifiedJsonString = JSON.stringify(modifiedJson, null, 2);
55008
+ const trimmed = originalResponse.trim();
55009
+ if (trimmed.match(/```json\s*\n([\s\S]*?)\n```/)) {
55010
+ return originalResponse.replace(/```json\s*\n([\s\S]*?)\n```/, `\`\`\`json
55011
+ ${modifiedJsonString}
55012
+ \`\`\``);
55013
+ } else if (trimmed.match(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/)) {
55014
+ return originalResponse.replace(/```\s*\n([{\[][\s\S]*?[}\]])\s*```/, `\`\`\`
55015
+ ${modifiedJsonString}
55016
+ \`\`\``);
55017
+ }
55018
+ return modifiedJsonString;
55019
+ }
54869
55020
  function replaceMermaidDiagramsInMarkdown(originalResponse, correctedDiagrams) {
54870
55021
  if (!originalResponse || typeof originalResponse !== "string") {
54871
55022
  return originalResponse;
@@ -54873,6 +55024,10 @@ function replaceMermaidDiagramsInMarkdown(originalResponse, correctedDiagrams) {
54873
55024
  if (!correctedDiagrams || correctedDiagrams.length === 0) {
54874
55025
  return originalResponse;
54875
55026
  }
55027
+ const hasJsonDiagrams = correctedDiagrams.some((d) => d.isInJson);
55028
+ if (hasJsonDiagrams) {
55029
+ return replaceMermaidDiagramsInJson(originalResponse, correctedDiagrams);
55030
+ }
54876
55031
  let modifiedResponse = originalResponse;
54877
55032
  const sortedDiagrams = [...correctedDiagrams].sort((a, b) => b.startIndex - a.startIndex);
54878
55033
  for (const diagram of sortedDiagrams) {
@@ -58538,21 +58693,20 @@ You are working with a repository located at: ${searchDirectory}
58538
58693
  if (assistantResponseContent) {
58539
58694
  await this.processImageReferences(assistantResponseContent);
58540
58695
  }
58541
- const validTools = [
58542
- "search",
58543
- "query",
58544
- "extract",
58545
- "listFiles",
58546
- "searchFiles",
58547
- "attempt_completion"
58548
- ];
58549
- if (this.allowEdit) {
58696
+ const validTools = [];
58697
+ if (this.allowedTools.isEnabled("search")) validTools.push("search");
58698
+ if (this.allowedTools.isEnabled("query")) validTools.push("query");
58699
+ if (this.allowedTools.isEnabled("extract")) validTools.push("extract");
58700
+ if (this.allowedTools.isEnabled("listFiles")) validTools.push("listFiles");
58701
+ if (this.allowedTools.isEnabled("searchFiles")) validTools.push("searchFiles");
58702
+ if (this.allowedTools.isEnabled("attempt_completion")) validTools.push("attempt_completion");
58703
+ if (this.allowEdit && this.allowedTools.isEnabled("implement")) {
58550
58704
  validTools.push("implement", "edit", "create");
58551
58705
  }
58552
- if (this.enableBash) {
58706
+ if (this.enableBash && this.allowedTools.isEnabled("bash")) {
58553
58707
  validTools.push("bash");
58554
58708
  }
58555
- if (this.enableDelegate) {
58709
+ if (this.enableDelegate && this.allowedTools.isEnabled("delegate")) {
58556
58710
  validTools.push("delegate");
58557
58711
  }
58558
58712
  const nativeTools = validTools;
@@ -58791,18 +58945,7 @@ Error: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(",
58791
58945
  break;
58792
58946
  }
58793
58947
  currentMessages.push({ role: "assistant", content: assistantResponseContent });
58794
- let reminderContent;
58795
- if (options.schema) {
58796
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
58797
-
58798
- Remember: Use proper XML format with BOTH opening and closing tags:
58799
-
58800
- <tool_name>
58801
- <parameter>value</parameter>
58802
- </tool_name>
58803
- ` + generateSchemaInstructions(options.schema, { debug: this.debug }).trim();
58804
- } else {
58805
- reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
58948
+ const reminderContent = `Please use one of the available tools to help answer the question, or use attempt_completion if you have enough information to provide a final answer.
58806
58949
 
58807
58950
  Remember: Use proper XML format with BOTH opening and closing tags:
58808
58951
 
@@ -58814,7 +58957,6 @@ Or for quick completion if your previous response was already correct and comple
58814
58957
  <attempt_complete>
58815
58958
 
58816
58959
  IMPORTANT: When using <attempt_complete>, this must be the ONLY content in your response. No additional text, explanations, or other content should be included. This tag signals to reuse your previous response as the final answer.`;
58817
- }
58818
58960
  currentMessages.push({
58819
58961
  role: "user",
58820
58962
  content: reminderContent