@probelabs/probe 0.6.0-rc278 → 0.6.0-rc280
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-rc280-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc280-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +114 -28
- package/build/agent/dsl/environment.js +1 -0
- package/build/agent/index.js +248 -87
- package/build/delegate.js +62 -23
- package/build/downloader.js +28 -25
- package/build/tools/analyzeAll.js +10 -10
- package/build/tools/common.js +4 -3
- package/build/tools/vercel.js +72 -10
- package/cjs/agent/ProbeAgent.cjs +251 -88
- package/cjs/index.cjs +248 -87
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +114 -28
- package/src/agent/dsl/environment.js +1 -0
- package/src/delegate.js +62 -23
- package/src/downloader.js +28 -25
- package/src/tools/analyzeAll.js +10 -10
- package/src/tools/common.js +4 -3
- package/src/tools/vercel.js +72 -10
- package/bin/binaries/probe-v0.6.0-rc278-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc278-x86_64-unknown-linux-musl.tar.gz +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -125,6 +125,27 @@ const MAX_HISTORY_MESSAGES = 100;
|
|
|
125
125
|
// Maximum image file size (20MB) to prevent OOM attacks
|
|
126
126
|
const MAX_IMAGE_FILE_SIZE = 20 * 1024 * 1024;
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Truncate a string for debug logging, showing first and last portion.
|
|
130
|
+
*/
|
|
131
|
+
export function debugTruncate(s, limit = 200) {
|
|
132
|
+
if (s.length <= limit) return s;
|
|
133
|
+
const half = Math.floor(limit / 2);
|
|
134
|
+
return s.substring(0, half) + ` ... [${s.length} chars] ... ` + s.substring(s.length - half);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Log tool results details for debug output.
|
|
139
|
+
*/
|
|
140
|
+
export function debugLogToolResults(toolResults) {
|
|
141
|
+
if (!toolResults || toolResults.length === 0) return;
|
|
142
|
+
for (const tr of toolResults) {
|
|
143
|
+
const argsStr = JSON.stringify(tr.args || {});
|
|
144
|
+
const resultStr = typeof tr.result === 'string' ? tr.result : JSON.stringify(tr.result || '');
|
|
145
|
+
console.log(`[DEBUG] tool: ${tr.toolName} | args: ${debugTruncate(argsStr)} | result: ${debugTruncate(resultStr)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
128
149
|
/**
|
|
129
150
|
* ProbeAgent class to handle AI interactions with code search capabilities
|
|
130
151
|
*/
|
|
@@ -193,6 +214,7 @@ export class ProbeAgent {
|
|
|
193
214
|
this.enableExecutePlan = !!options.enableExecutePlan;
|
|
194
215
|
this.debug = options.debug || process.env.DEBUG === '1';
|
|
195
216
|
this.cancelled = false;
|
|
217
|
+
this._abortController = new AbortController();
|
|
196
218
|
this.tracer = options.tracer || null;
|
|
197
219
|
this.outline = !!options.outline;
|
|
198
220
|
this.searchDelegate = options.searchDelegate !== undefined ? !!options.searchDelegate : true;
|
|
@@ -232,6 +254,7 @@ export class ProbeAgent {
|
|
|
232
254
|
// Supports exclusion with '!' prefix: ['*', '!bash'] = all tools except bash
|
|
233
255
|
// disableTools is a convenience flag that overrides allowedTools to []
|
|
234
256
|
const effectiveAllowedTools = options.disableTools ? [] : options.allowedTools;
|
|
257
|
+
this._rawAllowedTools = options.allowedTools; // Keep raw value for explicit tool checks
|
|
235
258
|
this.allowedTools = this._parseAllowedTools(effectiveAllowedTools);
|
|
236
259
|
|
|
237
260
|
// Storage adapter (defaults to in-memory)
|
|
@@ -459,6 +482,17 @@ export class ProbeAgent {
|
|
|
459
482
|
return mcpToolNames.filter(toolName => this._isMcpToolAllowed(toolName));
|
|
460
483
|
}
|
|
461
484
|
|
|
485
|
+
/**
|
|
486
|
+
* Check if query tool was explicitly listed in allowedTools (not via wildcard).
|
|
487
|
+
* Query (ast-grep) is excluded by default because models struggle with AST pattern syntax.
|
|
488
|
+
* @returns {boolean}
|
|
489
|
+
* @private
|
|
490
|
+
*/
|
|
491
|
+
_isQueryExplicitlyAllowed() {
|
|
492
|
+
if (!this._rawAllowedTools) return false;
|
|
493
|
+
return Array.isArray(this._rawAllowedTools) && this._rawAllowedTools.includes('query');
|
|
494
|
+
}
|
|
495
|
+
|
|
462
496
|
/**
|
|
463
497
|
* Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
|
|
464
498
|
* @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
|
|
@@ -792,6 +826,7 @@ export class ProbeAgent {
|
|
|
792
826
|
searchDelegateProvider: this.searchDelegateProvider,
|
|
793
827
|
searchDelegateModel: this.searchDelegateModel,
|
|
794
828
|
delegationManager: this.delegationManager, // Per-instance delegation limits
|
|
829
|
+
parentAbortSignal: this._abortController.signal, // Propagate cancellation to delegations
|
|
795
830
|
outputBuffer: this._outputBuffer,
|
|
796
831
|
concurrencyLimiter: this.concurrencyLimiter, // Global AI concurrency limiter
|
|
797
832
|
isToolAllowed,
|
|
@@ -814,7 +849,9 @@ export class ProbeAgent {
|
|
|
814
849
|
if (wrappedTools.searchToolInstance && isToolAllowed('search')) {
|
|
815
850
|
this.toolImplementations.search = wrappedTools.searchToolInstance;
|
|
816
851
|
}
|
|
817
|
-
|
|
852
|
+
// query tool (ast-grep) is not exposed to AI by default — models struggle with AST pattern syntax.
|
|
853
|
+
// Only register it when explicitly listed in allowedTools (not via wildcard '*').
|
|
854
|
+
if (wrappedTools.queryToolInstance && isToolAllowed('query') && this._isQueryExplicitlyAllowed()) {
|
|
818
855
|
this.toolImplementations.query = wrappedTools.queryToolInstance;
|
|
819
856
|
}
|
|
820
857
|
if (wrappedTools.extractToolInstance && isToolAllowed('extract')) {
|
|
@@ -1362,6 +1399,19 @@ export class ProbeAgent {
|
|
|
1362
1399
|
const controller = new AbortController();
|
|
1363
1400
|
const timeoutState = { timeoutId: null };
|
|
1364
1401
|
|
|
1402
|
+
// Link agent-level abort to this operation's controller
|
|
1403
|
+
// so that cancel() / cleanup() stops the current streamText call
|
|
1404
|
+
if (this._abortController.signal.aborted) {
|
|
1405
|
+
controller.abort();
|
|
1406
|
+
} else {
|
|
1407
|
+
const onAgentAbort = () => controller.abort();
|
|
1408
|
+
this._abortController.signal.addEventListener('abort', onAgentAbort, { once: true });
|
|
1409
|
+
// Clean up listener when this controller aborts (from any source)
|
|
1410
|
+
controller.signal.addEventListener('abort', () => {
|
|
1411
|
+
this._abortController.signal.removeEventListener('abort', onAgentAbort);
|
|
1412
|
+
}, { once: true });
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1365
1415
|
// Set up overall operation timeout (default 5 minutes)
|
|
1366
1416
|
if (this.maxOperationTimeout && this.maxOperationTimeout > 0) {
|
|
1367
1417
|
timeoutState.timeoutId = setTimeout(() => {
|
|
@@ -1729,7 +1779,8 @@ export class ProbeAgent {
|
|
|
1729
1779
|
allowEdit: this.allowEdit,
|
|
1730
1780
|
allowedTools: allowedToolsForDelegate,
|
|
1731
1781
|
debug: this.debug,
|
|
1732
|
-
tracer: this.tracer
|
|
1782
|
+
tracer: this.tracer,
|
|
1783
|
+
parentAbortSignal: this._abortController.signal
|
|
1733
1784
|
};
|
|
1734
1785
|
|
|
1735
1786
|
if (this.debug) {
|
|
@@ -1971,12 +2022,15 @@ export class ProbeAgent {
|
|
|
1971
2022
|
const toolMap = {
|
|
1972
2023
|
search: {
|
|
1973
2024
|
schema: searchSchema,
|
|
1974
|
-
description:
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
schema: querySchema,
|
|
1978
|
-
description: 'Search code using ast-grep structural pattern matching.'
|
|
2025
|
+
description: this.searchDelegate
|
|
2026
|
+
? 'Search code in the repository by asking a question. Accepts natural language questions — a subagent breaks them into targeted keyword searches and returns extracted code blocks. Do NOT formulate keyword queries yourself.'
|
|
2027
|
+
: 'Search code in the repository using keyword queries with Elasticsearch syntax. Handles stemming, case-insensitive matching, and camelCase/snake_case splitting automatically — do NOT try keyword variations manually.'
|
|
1979
2028
|
},
|
|
2029
|
+
// query tool (ast-grep) removed from AI-facing tools — models struggle with pattern syntax
|
|
2030
|
+
// query: {
|
|
2031
|
+
// schema: querySchema,
|
|
2032
|
+
// description: 'Search code using ast-grep structural pattern matching.'
|
|
2033
|
+
// },
|
|
1980
2034
|
extract: {
|
|
1981
2035
|
schema: extractSchema,
|
|
1982
2036
|
description: 'Extract code blocks from files based on file paths and optional line numbers.'
|
|
@@ -2812,10 +2866,12 @@ export class ProbeAgent {
|
|
|
2812
2866
|
}
|
|
2813
2867
|
|
|
2814
2868
|
// Add high-level instructions about when to use tools
|
|
2869
|
+
const searchToolDesc1 = this.searchDelegate
|
|
2870
|
+
? '- search: Ask natural language questions to find code (e.g., "How does authentication work?"). A subagent handles keyword searches and returns extracted code blocks. Do NOT formulate keyword queries — just ask questions.'
|
|
2871
|
+
: '- search: Find code patterns using keyword queries with Elasticsearch syntax. Handles stemming and case variations automatically — do NOT try manual keyword variations.';
|
|
2815
2872
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
2816
|
-
|
|
2873
|
+
${searchToolDesc1}
|
|
2817
2874
|
- extract: Extract specific code sections with context
|
|
2818
|
-
- query: Use AST patterns for structural code matching
|
|
2819
2875
|
- listFiles: Browse directory contents
|
|
2820
2876
|
- searchFiles: Find files by name patterns`;
|
|
2821
2877
|
|
|
@@ -2823,19 +2879,21 @@ export class ProbeAgent {
|
|
|
2823
2879
|
systemPrompt += `\n- bash: Execute bash commands for system operations`;
|
|
2824
2880
|
}
|
|
2825
2881
|
|
|
2826
|
-
const
|
|
2827
|
-
? '1. Start with search to
|
|
2828
|
-
: '1. Start with search to find relevant code patterns';
|
|
2829
|
-
const
|
|
2882
|
+
const searchGuidance1 = this.searchDelegate
|
|
2883
|
+
? '1. Start with search — ask a question about what you want to understand. It returns extracted code blocks directly.'
|
|
2884
|
+
: '1. Start with search to find relevant code patterns. One search per concept is usually enough — probe handles stemming and case variations.';
|
|
2885
|
+
const extractGuidance1 = this.searchDelegate
|
|
2830
2886
|
? '2. Use extract only if you need more context or a full file'
|
|
2831
2887
|
: '2. Use extract to get detailed context when needed';
|
|
2832
2888
|
|
|
2833
2889
|
systemPrompt += `\n
|
|
2834
2890
|
When exploring code:
|
|
2835
|
-
${
|
|
2836
|
-
${
|
|
2891
|
+
${searchGuidance1}
|
|
2892
|
+
${extractGuidance1}
|
|
2837
2893
|
3. Prefer focused, specific searches over broad queries
|
|
2838
|
-
4.
|
|
2894
|
+
4. Do NOT repeat the same search or try trivial keyword variations — probe handles stemming and case variations automatically
|
|
2895
|
+
5. If 2-3 consecutive searches return no results for a concept, stop searching for it — the term likely does not exist in that codebase
|
|
2896
|
+
6. Combine multiple tools to build complete understanding`;
|
|
2839
2897
|
|
|
2840
2898
|
// Add workspace context
|
|
2841
2899
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
@@ -2874,10 +2932,12 @@ ${extractGuidance}
|
|
|
2874
2932
|
}
|
|
2875
2933
|
|
|
2876
2934
|
// Add high-level instructions about when to use tools
|
|
2935
|
+
const searchToolDesc2 = this.searchDelegate
|
|
2936
|
+
? '- search: Ask natural language questions to find code (e.g., "How does authentication work?"). A subagent handles keyword searches and returns extracted code blocks. Do NOT formulate keyword queries — just ask questions.'
|
|
2937
|
+
: '- search: Find code patterns using keyword queries with Elasticsearch syntax. Handles stemming and case variations automatically — do NOT try manual keyword variations.';
|
|
2877
2938
|
systemPrompt += `You have access to powerful code search and analysis tools through MCP:
|
|
2878
|
-
|
|
2939
|
+
${searchToolDesc2}
|
|
2879
2940
|
- extract: Extract specific code sections with context
|
|
2880
|
-
- query: Use AST patterns for structural code matching
|
|
2881
2941
|
- listFiles: Browse directory contents
|
|
2882
2942
|
- searchFiles: Find files by name patterns`;
|
|
2883
2943
|
|
|
@@ -2885,19 +2945,21 @@ ${extractGuidance}
|
|
|
2885
2945
|
systemPrompt += `\n- bash: Execute bash commands for system operations`;
|
|
2886
2946
|
}
|
|
2887
2947
|
|
|
2888
|
-
const
|
|
2889
|
-
? '1. Start with search to
|
|
2890
|
-
: '1. Start with search to find relevant code patterns';
|
|
2891
|
-
const
|
|
2948
|
+
const searchGuidance2 = this.searchDelegate
|
|
2949
|
+
? '1. Start with search — ask a question about what you want to understand. It returns extracted code blocks directly.'
|
|
2950
|
+
: '1. Start with search to find relevant code patterns. One search per concept is usually enough — probe handles stemming and case variations.';
|
|
2951
|
+
const extractGuidance2 = this.searchDelegate
|
|
2892
2952
|
? '2. Use extract only if you need more context or a full file'
|
|
2893
2953
|
: '2. Use extract to get detailed context when needed';
|
|
2894
2954
|
|
|
2895
2955
|
systemPrompt += `\n
|
|
2896
2956
|
When exploring code:
|
|
2897
|
-
${
|
|
2898
|
-
${
|
|
2957
|
+
${searchGuidance2}
|
|
2958
|
+
${extractGuidance2}
|
|
2899
2959
|
3. Prefer focused, specific searches over broad queries
|
|
2900
|
-
4.
|
|
2960
|
+
4. Do NOT repeat the same search or try trivial keyword variations — probe handles stemming and case variations automatically
|
|
2961
|
+
5. If 2-3 consecutive searches return no results for a concept, stop searching for it — the term likely does not exist in that codebase
|
|
2962
|
+
6. Combine multiple tools to build complete understanding`;
|
|
2901
2963
|
|
|
2902
2964
|
// Add workspace context
|
|
2903
2965
|
if (this.allowedFolders && this.allowedFolders.length > 0) {
|
|
@@ -2953,10 +3015,10 @@ ${extractGuidance}
|
|
|
2953
3015
|
Follow these instructions carefully:
|
|
2954
3016
|
1. Analyze the user's request.
|
|
2955
3017
|
2. Use the available tools step-by-step to fulfill the request.
|
|
2956
|
-
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? '
|
|
3018
|
+
3. You should always prefer the search tool for code-related questions.${this.searchDelegate ? ' Ask natural language questions — the search subagent handles keyword formulation and returns extracted code blocks. Use extract only to expand context or read full files.' : ' Search handles stemming and case variations automatically — do NOT try keyword variations manually. Read full files only if really necessary.'}
|
|
2957
3019
|
4. Ensure to get really deep and understand the full picture before answering.
|
|
2958
3020
|
5. Once the task is fully completed, use the attempt_completion tool to provide the final result.
|
|
2959
|
-
6. Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results
|
|
3021
|
+
6. ${this.searchDelegate ? 'Ask clear, specific questions when searching. Each search should target a distinct concept or question.' : 'Prefer concise and focused search queries. Use specific keywords and phrases to narrow down results.'}${this.allowEdit ? `
|
|
2960
3022
|
7. When modifying files, choose the appropriate tool:
|
|
2961
3023
|
- Use 'edit' for all code modifications:
|
|
2962
3024
|
* PREFERRED: Use start_line (and optionally end_line) for line-targeted editing — this is the safest and most precise approach.${this.hashLines ? ' Use the line:hash references from extract/search output (e.g. "42:ab") for integrity verification.' : ''} Always use extract first to see line numbers${this.hashLines ? ' and hashes' : ''}, then edit by line reference.
|
|
@@ -3369,6 +3431,11 @@ Follow these instructions carefully:
|
|
|
3369
3431
|
completionAttempted = true;
|
|
3370
3432
|
}, toolContext);
|
|
3371
3433
|
|
|
3434
|
+
if (this.debug) {
|
|
3435
|
+
const toolNames = Object.keys(tools);
|
|
3436
|
+
console.log(`[DEBUG] Agent tools registered (${toolNames.length}): ${toolNames.join(', ')}`);
|
|
3437
|
+
}
|
|
3438
|
+
|
|
3372
3439
|
let maxResponseTokens = this.maxResponseTokens;
|
|
3373
3440
|
if (!maxResponseTokens) {
|
|
3374
3441
|
maxResponseTokens = 4000;
|
|
@@ -3418,6 +3485,7 @@ Follow these instructions carefully:
|
|
|
3418
3485
|
|
|
3419
3486
|
if (this.debug) {
|
|
3420
3487
|
console.log(`[DEBUG] Step ${currentIteration}/${maxIterations} finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
3488
|
+
debugLogToolResults(toolResults);
|
|
3421
3489
|
}
|
|
3422
3490
|
}
|
|
3423
3491
|
};
|
|
@@ -3629,6 +3697,7 @@ Double-check your response based on the criteria above. If everything looks good
|
|
|
3629
3697
|
}
|
|
3630
3698
|
if (this.debug) {
|
|
3631
3699
|
console.log(`[DEBUG] Completion prompt step finished (reason: ${finishReason}, tools: ${toolResults?.length || 0})`);
|
|
3700
|
+
debugLogToolResults(toolResults);
|
|
3632
3701
|
}
|
|
3633
3702
|
}
|
|
3634
3703
|
};
|
|
@@ -4545,6 +4614,11 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
4545
4614
|
* Clean up resources (including MCP connections)
|
|
4546
4615
|
*/
|
|
4547
4616
|
async cleanup() {
|
|
4617
|
+
// Abort any in-flight operations (delegations, streaming, etc.)
|
|
4618
|
+
if (!this._abortController.signal.aborted) {
|
|
4619
|
+
this._abortController.abort();
|
|
4620
|
+
}
|
|
4621
|
+
|
|
4548
4622
|
// Clean up MCP bridge
|
|
4549
4623
|
if (this.mcpBridge) {
|
|
4550
4624
|
try {
|
|
@@ -4574,12 +4648,24 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
4574
4648
|
}
|
|
4575
4649
|
|
|
4576
4650
|
/**
|
|
4577
|
-
* Cancel the current request
|
|
4651
|
+
* Cancel the current request and all in-flight delegations.
|
|
4652
|
+
* Aborts the internal AbortController so streamText, subagents,
|
|
4653
|
+
* and any code checking the signal will stop.
|
|
4578
4654
|
*/
|
|
4579
4655
|
cancel() {
|
|
4580
4656
|
this.cancelled = true;
|
|
4657
|
+
this._abortController.abort();
|
|
4581
4658
|
if (this.debug) {
|
|
4582
4659
|
console.log(`[DEBUG] Agent cancelled for session ${this.sessionId}`);
|
|
4583
4660
|
}
|
|
4584
4661
|
}
|
|
4662
|
+
|
|
4663
|
+
/**
|
|
4664
|
+
* Get the abort signal for this agent.
|
|
4665
|
+
* Delegations and subagents should check this signal.
|
|
4666
|
+
* @returns {AbortSignal}
|
|
4667
|
+
*/
|
|
4668
|
+
get abortSignal() {
|
|
4669
|
+
return this._abortController.signal;
|
|
4670
|
+
}
|
|
4585
4671
|
}
|
|
@@ -284,6 +284,7 @@ export function generateSandboxGlobals(options) {
|
|
|
284
284
|
results.push(p);
|
|
285
285
|
|
|
286
286
|
if (executing.size >= mapConcurrency) {
|
|
287
|
+
console.error(`[map] Concurrency limit reached (${executing.size}/${mapConcurrency}), waiting for a slot...`);
|
|
287
288
|
await Promise.race(executing);
|
|
288
289
|
}
|
|
289
290
|
}
|