@probelabs/probe 0.6.0-rc210 → 0.6.0-rc212
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/bin/binaries/probe-v0.6.0-rc212-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc212-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc212-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc212-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc212-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +19 -3
- package/build/agent/index.js +639 -75
- package/build/agent/probeTool.js +11 -2
- package/build/agent/tools.js +8 -0
- package/build/index.js +6 -1
- package/build/search.js +2 -2
- package/build/tools/analyzeAll.js +624 -0
- package/build/tools/common.js +149 -85
- package/build/tools/langchain.js +1 -1
- package/build/tools/vercel.js +61 -2
- package/cjs/agent/ProbeAgent.cjs +9698 -6756
- package/cjs/index.cjs +9702 -6754
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +19 -3
- package/src/agent/probeTool.js +11 -2
- package/src/agent/tools.js +8 -0
- package/src/index.js +6 -1
- package/src/search.js +2 -2
- package/src/tools/analyzeAll.js +624 -0
- package/src/tools/common.js +149 -85
- package/src/tools/langchain.js +1 -1
- package/src/tools/vercel.js +61 -2
- package/bin/binaries/probe-v0.6.0-rc210-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc210-x86_64-unknown-linux-musl.tar.gz +0 -0
package/build/tools/common.js
CHANGED
|
@@ -46,6 +46,11 @@ export const bashSchema = z.object({
|
|
|
46
46
|
env: z.record(z.string()).optional().describe('Additional environment variables (optional)')
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
+
export const analyzeAllSchema = z.object({
|
|
50
|
+
question: z.string().min(1).describe('Free-form question to answer (e.g., "What features are customers using?", "List all API endpoints"). The AI will automatically plan the search strategy, process all matching data, and synthesize a comprehensive answer.'),
|
|
51
|
+
path: z.string().optional().default('.').describe('Directory path to search in')
|
|
52
|
+
});
|
|
53
|
+
|
|
49
54
|
// Schema for the attempt_completion tool - flexible validation for direct XML response
|
|
50
55
|
export const attemptCompletionSchema = {
|
|
51
56
|
// Custom validation that requires result parameter but allows direct XML response
|
|
@@ -273,6 +278,52 @@ I have refactored the search module according to the requirements and verified t
|
|
|
273
278
|
</attempt_completion>
|
|
274
279
|
`;
|
|
275
280
|
|
|
281
|
+
export const analyzeAllToolDefinition = `
|
|
282
|
+
## analyze_all
|
|
283
|
+
Description: Intelligent bulk data analysis tool. Process ALL data matching your question using a 3-phase approach:
|
|
284
|
+
1. **PLANNING**: AI analyzes your question and determines the optimal search strategy
|
|
285
|
+
2. **PROCESSING**: Map-reduce processes all matching data in parallel chunks
|
|
286
|
+
3. **SYNTHESIS**: Comprehensive answer with evidence and organization
|
|
287
|
+
|
|
288
|
+
**Use this for questions requiring 100% data coverage:**
|
|
289
|
+
- "What features are customers using?"
|
|
290
|
+
- "List all API endpoints in the codebase"
|
|
291
|
+
- "Summarize the error handling patterns"
|
|
292
|
+
- "Count all TODO comments and their contexts"
|
|
293
|
+
|
|
294
|
+
**Do NOT use for:**
|
|
295
|
+
- Simple searches where a sample is sufficient
|
|
296
|
+
- Finding a specific function or class
|
|
297
|
+
- Quick exploration (use search instead)
|
|
298
|
+
|
|
299
|
+
**WARNING:** Makes multiple LLM calls - slower and costlier than search.
|
|
300
|
+
|
|
301
|
+
Parameters:
|
|
302
|
+
- question: (required) Free-form question to answer - the AI determines the best search strategy automatically
|
|
303
|
+
- path: (optional) Directory to search in (default: current directory)
|
|
304
|
+
|
|
305
|
+
<examples>
|
|
306
|
+
|
|
307
|
+
User: What are all the different tools available in this codebase?
|
|
308
|
+
<analyze_all>
|
|
309
|
+
<question>What are all the different tools available in this codebase and what do they do?</question>
|
|
310
|
+
<path>./src</path>
|
|
311
|
+
</analyze_all>
|
|
312
|
+
|
|
313
|
+
User: I need to understand all the error handling patterns
|
|
314
|
+
<analyze_all>
|
|
315
|
+
<question>What error handling patterns are used throughout the codebase? Include examples.</question>
|
|
316
|
+
</analyze_all>
|
|
317
|
+
|
|
318
|
+
User: Count and categorize all the environment variables
|
|
319
|
+
<analyze_all>
|
|
320
|
+
<question>What environment variables are used? Categorize them by purpose.</question>
|
|
321
|
+
<path>./src</path>
|
|
322
|
+
</analyze_all>
|
|
323
|
+
|
|
324
|
+
</examples>
|
|
325
|
+
`;
|
|
326
|
+
|
|
276
327
|
export const bashToolDefinition = `
|
|
277
328
|
## bash
|
|
278
329
|
Description: Execute bash commands for system exploration and development tasks. This tool has built-in security with allow/deny lists. By default, only safe read-only commands are allowed for code exploration.
|
|
@@ -334,6 +385,7 @@ export const queryDescription = 'Search code using ast-grep structural pattern m
|
|
|
334
385
|
export const extractDescription = 'Extract code blocks from files based on file paths and optional line numbers. Use this tool to see complete context after finding relevant files.';
|
|
335
386
|
export const delegateDescription = 'Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Used by AI agents to break down complex requests into focused, parallel tasks.';
|
|
336
387
|
export const bashDescription = 'Execute bash commands for system exploration and development tasks. Secure by default with built-in allow/deny lists.';
|
|
388
|
+
export const analyzeAllDescription = 'Answer questions that require analyzing ALL matching data in the codebase. Use for aggregate questions like "What features exist?", "List all API endpoints", "Count TODO comments". The AI automatically plans the search strategy, processes all results via map-reduce, and synthesizes a comprehensive answer. WARNING: Slower than search - only use when you need complete coverage.';
|
|
337
389
|
|
|
338
390
|
// Valid tool names that should be parsed as tool calls
|
|
339
391
|
// This is the canonical list - all other tool lists should reference this
|
|
@@ -342,6 +394,7 @@ export const DEFAULT_VALID_TOOLS = [
|
|
|
342
394
|
'query',
|
|
343
395
|
'extract',
|
|
344
396
|
'delegate',
|
|
397
|
+
'analyze_all',
|
|
345
398
|
'listSkills',
|
|
346
399
|
'useSkill',
|
|
347
400
|
'listFiles',
|
|
@@ -379,6 +432,7 @@ function getValidParamsForTool(toolName) {
|
|
|
379
432
|
query: querySchema,
|
|
380
433
|
extract: extractSchema,
|
|
381
434
|
delegate: delegateSchema,
|
|
435
|
+
analyze_all: analyzeAllSchema,
|
|
382
436
|
listSkills: listSkillsSchema,
|
|
383
437
|
useSkill: useSkillSchema,
|
|
384
438
|
bash: bashSchema,
|
|
@@ -416,115 +470,125 @@ function getValidParamsForTool(toolName) {
|
|
|
416
470
|
|
|
417
471
|
// Simple XML parser helper - safer string-based approach
|
|
418
472
|
export function parseXmlToolCall(xmlString, validTools = DEFAULT_VALID_TOOLS) {
|
|
419
|
-
//
|
|
473
|
+
// Find the tool that appears EARLIEST in the string
|
|
474
|
+
// This prevents parameter tags (like <query> inside <analyze_all>) from being matched as tools
|
|
475
|
+
let earliestToolName = null;
|
|
476
|
+
let earliestOpenIndex = Infinity;
|
|
477
|
+
|
|
420
478
|
for (const toolName of validTools) {
|
|
421
479
|
const openTag = `<${toolName}>`;
|
|
422
|
-
const closeTag = `</${toolName}>`;
|
|
423
|
-
|
|
424
480
|
const openIndex = xmlString.indexOf(openTag);
|
|
425
|
-
if (openIndex
|
|
426
|
-
|
|
481
|
+
if (openIndex !== -1 && openIndex < earliestOpenIndex) {
|
|
482
|
+
earliestOpenIndex = openIndex;
|
|
483
|
+
earliestToolName = toolName;
|
|
427
484
|
}
|
|
485
|
+
}
|
|
428
486
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
if (toolName === 'attempt_completion') {
|
|
434
|
-
// Find the last occurrence of the closing tag in the entire string
|
|
435
|
-
// This assumes attempt_completion doesn't have nested tags of the same name
|
|
436
|
-
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
437
|
-
// Make sure the closing tag is after the opening tag
|
|
438
|
-
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
439
|
-
closeIndex = -1; // Invalid, treat as no closing tag
|
|
440
|
-
}
|
|
441
|
-
} else {
|
|
442
|
-
closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
|
|
443
|
-
}
|
|
487
|
+
// No valid tool found
|
|
488
|
+
if (earliestToolName === null) {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
444
491
|
|
|
445
|
-
|
|
492
|
+
const toolName = earliestToolName;
|
|
493
|
+
const openTag = `<${toolName}>`;
|
|
494
|
+
const closeTag = `</${toolName}>`;
|
|
495
|
+
const openIndex = earliestOpenIndex;
|
|
446
496
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
497
|
+
// For attempt_completion, use lastIndexOf to find the LAST occurrence of closing tag
|
|
498
|
+
// This prevents issues where the content contains the closing tag string (e.g., in regex patterns)
|
|
499
|
+
// For other tools, use indexOf from the opening tag position
|
|
500
|
+
let closeIndex;
|
|
501
|
+
if (toolName === 'attempt_completion') {
|
|
502
|
+
// Find the last occurrence of the closing tag in the entire string
|
|
503
|
+
// This assumes attempt_completion doesn't have nested tags of the same name
|
|
504
|
+
closeIndex = xmlString.lastIndexOf(closeTag);
|
|
505
|
+
// Make sure the closing tag is after the opening tag
|
|
506
|
+
if (closeIndex !== -1 && closeIndex <= openIndex + openTag.length) {
|
|
507
|
+
closeIndex = -1; // Invalid, treat as no closing tag
|
|
451
508
|
}
|
|
509
|
+
} else {
|
|
510
|
+
closeIndex = xmlString.indexOf(closeTag, openIndex + openTag.length);
|
|
511
|
+
}
|
|
452
512
|
|
|
453
|
-
|
|
454
|
-
const innerContent = xmlString.substring(
|
|
455
|
-
openIndex + openTag.length,
|
|
456
|
-
closeIndex
|
|
457
|
-
);
|
|
513
|
+
let hasClosingTag = closeIndex !== -1;
|
|
458
514
|
|
|
459
|
-
|
|
515
|
+
// If no closing tag found, use content until end of string
|
|
516
|
+
// This makes the parser more resilient to AI formatting errors
|
|
517
|
+
if (closeIndex === -1) {
|
|
518
|
+
closeIndex = xmlString.length;
|
|
519
|
+
}
|
|
460
520
|
|
|
461
|
-
|
|
462
|
-
|
|
521
|
+
// Extract the content between tags (or until end if no closing tag)
|
|
522
|
+
const innerContent = xmlString.substring(
|
|
523
|
+
openIndex + openTag.length,
|
|
524
|
+
closeIndex
|
|
525
|
+
);
|
|
463
526
|
|
|
464
|
-
|
|
465
|
-
// Only look for parameters that are valid for this specific tool
|
|
466
|
-
for (const paramName of validParams) {
|
|
467
|
-
const paramOpenTag = `<${paramName}>`;
|
|
468
|
-
const paramCloseTag = `</${paramName}>`;
|
|
527
|
+
const params = {};
|
|
469
528
|
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
continue; // Parameter not found
|
|
473
|
-
}
|
|
529
|
+
// Get valid parameters for this specific tool from its schema
|
|
530
|
+
const validParams = getValidParamsForTool(toolName);
|
|
474
531
|
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
nextTagIndex = nextIndex;
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
paramCloseIndex = nextTagIndex;
|
|
489
|
-
}
|
|
532
|
+
// Parse parameters using string-based approach for better safety
|
|
533
|
+
// Only look for parameters that are valid for this specific tool
|
|
534
|
+
for (const paramName of validParams) {
|
|
535
|
+
const paramOpenTag = `<${paramName}>`;
|
|
536
|
+
const paramCloseTag = `</${paramName}>`;
|
|
537
|
+
|
|
538
|
+
const paramOpenIndex = innerContent.indexOf(paramOpenTag);
|
|
539
|
+
if (paramOpenIndex === -1) {
|
|
540
|
+
continue; // Parameter not found
|
|
541
|
+
}
|
|
490
542
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
// Check if it's potentially a number (handle integers and floats)
|
|
503
|
-
const num = Number(paramValue);
|
|
504
|
-
if (Number.isFinite(num)) { // Use Number.isFinite to avoid Infinity/NaN
|
|
505
|
-
paramValue = num;
|
|
543
|
+
let paramCloseIndex = innerContent.indexOf(paramCloseTag, paramOpenIndex + paramOpenTag.length);
|
|
544
|
+
|
|
545
|
+
// Handle unclosed parameter tags - use content until next tag or end of content
|
|
546
|
+
if (paramCloseIndex === -1) {
|
|
547
|
+
// Find the next opening tag after this parameter
|
|
548
|
+
let nextTagIndex = innerContent.length;
|
|
549
|
+
for (const nextParam of validParams) {
|
|
550
|
+
const nextOpenTag = `<${nextParam}>`;
|
|
551
|
+
const nextIndex = innerContent.indexOf(nextOpenTag, paramOpenIndex + paramOpenTag.length);
|
|
552
|
+
if (nextIndex !== -1 && nextIndex < nextTagIndex) {
|
|
553
|
+
nextTagIndex = nextIndex;
|
|
506
554
|
}
|
|
507
|
-
// Keep as string if not a valid finite number
|
|
508
555
|
}
|
|
509
|
-
|
|
510
|
-
params[paramName] = paramValue;
|
|
556
|
+
paramCloseIndex = nextTagIndex;
|
|
511
557
|
}
|
|
512
558
|
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
559
|
+
let paramValue = innerContent.substring(
|
|
560
|
+
paramOpenIndex + paramOpenTag.length,
|
|
561
|
+
paramCloseIndex
|
|
562
|
+
).trim();
|
|
563
|
+
|
|
564
|
+
// Basic type inference (can be improved)
|
|
565
|
+
if (paramValue.toLowerCase() === 'true') {
|
|
566
|
+
paramValue = true;
|
|
567
|
+
} else if (paramValue.toLowerCase() === 'false') {
|
|
568
|
+
paramValue = false;
|
|
569
|
+
} else if (!isNaN(paramValue) && paramValue.trim() !== '') {
|
|
570
|
+
// Check if it's potentially a number (handle integers and floats)
|
|
571
|
+
const num = Number(paramValue);
|
|
572
|
+
if (Number.isFinite(num)) { // Use Number.isFinite to avoid Infinity/NaN
|
|
573
|
+
paramValue = num;
|
|
519
574
|
}
|
|
575
|
+
// Keep as string if not a valid finite number
|
|
520
576
|
}
|
|
521
577
|
|
|
522
|
-
|
|
523
|
-
return { toolName, params };
|
|
578
|
+
params[paramName] = paramValue;
|
|
524
579
|
}
|
|
525
580
|
|
|
526
|
-
//
|
|
527
|
-
|
|
581
|
+
// Special handling for attempt_completion - use entire inner content as result
|
|
582
|
+
if (toolName === 'attempt_completion') {
|
|
583
|
+
params['result'] = innerContent.trim();
|
|
584
|
+
// Remove command parameter if it was parsed by generic logic above (legacy compatibility)
|
|
585
|
+
if (params.command) {
|
|
586
|
+
delete params.command;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Return the parsed tool call
|
|
591
|
+
return { toolName, params };
|
|
528
592
|
}
|
|
529
593
|
|
|
530
594
|
/**
|
package/build/tools/langchain.js
CHANGED
|
@@ -16,7 +16,7 @@ export function createSearchTool(options = {}) {
|
|
|
16
16
|
name: 'search',
|
|
17
17
|
description: searchDescription,
|
|
18
18
|
schema: searchSchema,
|
|
19
|
-
func: async ({ query: searchQuery, path, allow_tests, exact, maxResults, maxTokens =
|
|
19
|
+
func: async ({ query: searchQuery, path, allow_tests, exact, maxResults, maxTokens = 20000, language }) => {
|
|
20
20
|
try {
|
|
21
21
|
const results = await search({
|
|
22
22
|
query: searchQuery,
|
package/build/tools/vercel.js
CHANGED
|
@@ -8,7 +8,8 @@ import { search } from '../search.js';
|
|
|
8
8
|
import { query } from '../query.js';
|
|
9
9
|
import { extract } from '../extract.js';
|
|
10
10
|
import { delegate } from '../delegate.js';
|
|
11
|
-
import {
|
|
11
|
+
import { analyzeAll } from './analyzeAll.js';
|
|
12
|
+
import { searchSchema, querySchema, extractSchema, delegateSchema, analyzeAllSchema, searchDescription, queryDescription, extractDescription, delegateDescription, analyzeAllDescription, parseTargets, parseAndResolvePaths, resolveTargetPath } from './common.js';
|
|
12
13
|
import { formatErrorForAI } from '../utils/error-types.js';
|
|
13
14
|
|
|
14
15
|
const CODE_SEARCH_SCHEMA = {
|
|
@@ -156,7 +157,7 @@ function buildSearchDelegateTask({ searchQuery, searchPath, exact, language, all
|
|
|
156
157
|
export const searchTool = (options = {}) => {
|
|
157
158
|
const {
|
|
158
159
|
sessionId,
|
|
159
|
-
maxTokens =
|
|
160
|
+
maxTokens = 20000,
|
|
160
161
|
debug = false,
|
|
161
162
|
outline = false,
|
|
162
163
|
searchDelegate = false
|
|
@@ -568,3 +569,61 @@ export const delegateTool = (options = {}) => {
|
|
|
568
569
|
}
|
|
569
570
|
});
|
|
570
571
|
};
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Analyze All tool generator - intelligent 3-phase analysis using map-reduce
|
|
575
|
+
*
|
|
576
|
+
* @param {Object} [options] - Configuration options
|
|
577
|
+
* @param {string} [options.sessionId] - Session ID for caching
|
|
578
|
+
* @param {boolean} [options.debug=false] - Enable debug logging
|
|
579
|
+
* @param {string} [options.cwd] - Working directory
|
|
580
|
+
* @param {string[]} [options.allowedFolders] - Allowed folders
|
|
581
|
+
* @param {string} [options.provider] - AI provider
|
|
582
|
+
* @param {string} [options.model] - AI model
|
|
583
|
+
* @param {Object} [options.tracer] - Telemetry tracer
|
|
584
|
+
* @returns {Object} Configured analyze_all tool
|
|
585
|
+
*/
|
|
586
|
+
export const analyzeAllTool = (options = {}) => {
|
|
587
|
+
const { sessionId, debug = false } = options;
|
|
588
|
+
|
|
589
|
+
return tool({
|
|
590
|
+
name: 'analyze_all',
|
|
591
|
+
description: analyzeAllDescription,
|
|
592
|
+
inputSchema: analyzeAllSchema,
|
|
593
|
+
execute: async ({ question, path }) => {
|
|
594
|
+
try {
|
|
595
|
+
// Parse and resolve path if provided
|
|
596
|
+
let searchPath = path || '.';
|
|
597
|
+
if (path && options.cwd) {
|
|
598
|
+
const resolvedPaths = parseAndResolvePaths(path, options.cwd);
|
|
599
|
+
if (resolvedPaths.length > 0) {
|
|
600
|
+
searchPath = resolvedPaths[0];
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
if (debug) {
|
|
605
|
+
console.error(`[analyze_all] Starting analysis`);
|
|
606
|
+
console.error(`[analyze_all] Question: ${question}`);
|
|
607
|
+
console.error(`[analyze_all] Path: ${searchPath}`);
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
const result = await analyzeAll({
|
|
611
|
+
question,
|
|
612
|
+
path: searchPath,
|
|
613
|
+
sessionId,
|
|
614
|
+
debug,
|
|
615
|
+
cwd: options.cwd,
|
|
616
|
+
allowedFolders: options.allowedFolders,
|
|
617
|
+
provider: options.provider,
|
|
618
|
+
model: options.model,
|
|
619
|
+
tracer: options.tracer
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
return result;
|
|
623
|
+
} catch (error) {
|
|
624
|
+
console.error('Error executing analyze_all:', error);
|
|
625
|
+
return formatErrorForAI(error);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
});
|
|
629
|
+
};
|