@probelabs/probe 0.6.0-rc88 → 0.6.0-rc89
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/probe-binary +0 -0
- package/build/agent/ProbeAgent.d.ts +8 -0
- package/build/agent/ProbeAgent.js +180 -15
- package/build/agent/acp/tools.js +4 -4
- package/build/agent/acp/tools.test.js +11 -11
- package/build/agent/index.js +889 -29
- package/build/agent/mcp/client.js +338 -0
- package/build/agent/mcp/config.js +313 -0
- package/build/agent/mcp/index.js +64 -0
- package/build/agent/mcp/xmlBridge.js +371 -0
- package/build/agent/mockProvider.js +53 -0
- package/build/agent/schemaUtils.js +33 -18
- package/build/agent/tokenCounter.js +19 -0
- package/build/tools/vercel.js +4 -4
- package/cjs/agent/ProbeAgent.cjs +886 -26
- package/cjs/index.cjs +893 -33
- package/index.d.ts +8 -0
- package/package.json +11 -7
- package/src/agent/ProbeAgent.d.ts +8 -0
- package/src/agent/ProbeAgent.js +180 -15
- package/src/agent/acp/tools.js +4 -4
- package/src/agent/acp/tools.test.js +11 -11
- package/src/agent/mcp/client.js +338 -0
- package/src/agent/mcp/config.js +313 -0
- package/src/agent/mcp/index.js +64 -0
- package/src/agent/mcp/xmlBridge.js +371 -0
- package/src/agent/mockProvider.js +53 -0
- package/src/agent/schemaUtils.js +33 -18
- package/src/agent/tokenCounter.js +19 -0
- package/src/tools/vercel.js +4 -4
package/bin/probe-binary
ADDED
|
Binary file
|
|
@@ -23,6 +23,14 @@ export interface ProbeAgentOptions {
|
|
|
23
23
|
debug?: boolean;
|
|
24
24
|
/** Optional telemetry tracer instance */
|
|
25
25
|
tracer?: any;
|
|
26
|
+
/** Enable MCP (Model Context Protocol) tool integration */
|
|
27
|
+
enableMcp?: boolean;
|
|
28
|
+
/** Path to MCP configuration file */
|
|
29
|
+
mcpConfigPath?: string;
|
|
30
|
+
/** MCP configuration object (overrides mcpConfigPath) */
|
|
31
|
+
mcpConfig?: any;
|
|
32
|
+
/** @deprecated Use mcpConfig instead */
|
|
33
|
+
mcpServers?: any[];
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
/**
|
|
@@ -19,14 +19,15 @@ import {
|
|
|
19
19
|
parseXmlToolCallWithThinking
|
|
20
20
|
} from './tools.js';
|
|
21
21
|
import { createMessagePreview } from '../tools/common.js';
|
|
22
|
-
import {
|
|
23
|
-
createWrappedTools,
|
|
24
|
-
listFilesToolInstance,
|
|
22
|
+
import {
|
|
23
|
+
createWrappedTools,
|
|
24
|
+
listFilesToolInstance,
|
|
25
25
|
searchFilesToolInstance,
|
|
26
|
-
clearToolExecutionData
|
|
26
|
+
clearToolExecutionData
|
|
27
27
|
} from './probeTool.js';
|
|
28
|
+
import { createMockProvider } from './mockProvider.js';
|
|
28
29
|
import { listFilesByLevel } from '../index.js';
|
|
29
|
-
import {
|
|
30
|
+
import {
|
|
30
31
|
cleanSchemaResponse,
|
|
31
32
|
isJsonSchema,
|
|
32
33
|
validateJsonResponse,
|
|
@@ -35,6 +36,11 @@ import {
|
|
|
35
36
|
createSchemaDefinitionCorrectionPrompt,
|
|
36
37
|
validateAndFixMermaidResponse
|
|
37
38
|
} from './schemaUtils.js';
|
|
39
|
+
import {
|
|
40
|
+
MCPXmlBridge,
|
|
41
|
+
parseHybridXmlToolCall,
|
|
42
|
+
loadMCPConfigurationFromPath
|
|
43
|
+
} from './mcp/index.js';
|
|
38
44
|
|
|
39
45
|
// Maximum tool iterations to prevent infinite loops - configurable via MAX_TOOL_ITERATIONS env var
|
|
40
46
|
const MAX_TOOL_ITERATIONS = parseInt(process.env.MAX_TOOL_ITERATIONS || '30', 10);
|
|
@@ -58,6 +64,10 @@ export class ProbeAgent {
|
|
|
58
64
|
* @param {boolean} [options.outline] - Enable outline-xml format for search results
|
|
59
65
|
* @param {number} [options.maxResponseTokens] - Maximum tokens for AI responses
|
|
60
66
|
* @param {boolean} [options.disableMermaidValidation=false] - Disable automatic mermaid diagram validation and fixing
|
|
67
|
+
* @param {boolean} [options.enableMcp=false] - Enable MCP tool integration
|
|
68
|
+
* @param {string} [options.mcpConfigPath] - Path to MCP configuration file
|
|
69
|
+
* @param {Object} [options.mcpConfig] - MCP configuration object (overrides mcpConfigPath)
|
|
70
|
+
* @param {Array} [options.mcpServers] - Deprecated, use mcpConfig instead
|
|
61
71
|
*/
|
|
62
72
|
constructor(options = {}) {
|
|
63
73
|
// Basic configuration
|
|
@@ -92,14 +102,29 @@ export class ProbeAgent {
|
|
|
92
102
|
// Initialize tools
|
|
93
103
|
this.initializeTools();
|
|
94
104
|
|
|
95
|
-
// Initialize the AI model
|
|
96
|
-
this.initializeModel();
|
|
97
|
-
|
|
98
105
|
// Initialize chat history
|
|
99
106
|
this.history = [];
|
|
100
|
-
|
|
107
|
+
|
|
101
108
|
// Initialize event emitter for tool execution updates
|
|
102
109
|
this.events = new EventEmitter();
|
|
110
|
+
|
|
111
|
+
// MCP configuration
|
|
112
|
+
this.enableMcp = !!options.enableMcp || process.env.ENABLE_MCP === '1';
|
|
113
|
+
this.mcpConfigPath = options.mcpConfigPath || null;
|
|
114
|
+
this.mcpConfig = options.mcpConfig || null;
|
|
115
|
+
this.mcpServers = options.mcpServers || null; // Deprecated, keep for backward compatibility
|
|
116
|
+
this.mcpBridge = null;
|
|
117
|
+
|
|
118
|
+
// Initialize the AI model
|
|
119
|
+
this.initializeModel();
|
|
120
|
+
|
|
121
|
+
// Initialize MCP if enabled
|
|
122
|
+
if (this.enableMcp) {
|
|
123
|
+
this.initializeMCP().catch(error => {
|
|
124
|
+
console.error('[MCP] Failed to initialize MCP:', error);
|
|
125
|
+
this.mcpBridge = null;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
103
128
|
}
|
|
104
129
|
|
|
105
130
|
/**
|
|
@@ -138,6 +163,12 @@ export class ProbeAgent {
|
|
|
138
163
|
* Initialize the AI model based on available API keys and forced provider setting
|
|
139
164
|
*/
|
|
140
165
|
initializeModel() {
|
|
166
|
+
// Check if we're in test mode and should use mock provider
|
|
167
|
+
if (process.env.NODE_ENV === 'test' || process.env.USE_MOCK_AI === 'true') {
|
|
168
|
+
this.initializeMockModel();
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
141
172
|
// Get API keys from environment variables
|
|
142
173
|
const anthropicApiKey = process.env.ANTHROPIC_API_KEY;
|
|
143
174
|
const openaiApiKey = process.env.OPENAI_API_KEY;
|
|
@@ -231,12 +262,83 @@ export class ProbeAgent {
|
|
|
231
262
|
});
|
|
232
263
|
this.model = modelName || 'gemini-2.5-pro';
|
|
233
264
|
this.apiType = 'google';
|
|
234
|
-
|
|
265
|
+
|
|
235
266
|
if (this.debug) {
|
|
236
267
|
console.log(`Using Google API with model: ${this.model}${apiUrl ? ` (URL: ${apiUrl})` : ''}`);
|
|
237
268
|
}
|
|
238
269
|
}
|
|
239
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Initialize mock model for testing
|
|
273
|
+
*/
|
|
274
|
+
initializeMockModel(modelName) {
|
|
275
|
+
this.provider = createMockProvider();
|
|
276
|
+
this.model = modelName || 'mock-model';
|
|
277
|
+
this.apiType = 'mock';
|
|
278
|
+
|
|
279
|
+
if (this.debug) {
|
|
280
|
+
console.log(`Using Mock API with model: ${this.model}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Initialize MCP bridge and load tools
|
|
286
|
+
*/
|
|
287
|
+
async initializeMCP() {
|
|
288
|
+
if (!this.enableMcp) return;
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
let mcpConfig = null;
|
|
292
|
+
|
|
293
|
+
// Priority order: mcpConfig > mcpConfigPath > mcpServers (deprecated) > auto-discovery
|
|
294
|
+
if (this.mcpConfig) {
|
|
295
|
+
// Direct config object provided (SDK usage)
|
|
296
|
+
mcpConfig = this.mcpConfig;
|
|
297
|
+
if (this.debug) {
|
|
298
|
+
console.log('[DEBUG] Using provided MCP config object');
|
|
299
|
+
}
|
|
300
|
+
} else if (this.mcpConfigPath) {
|
|
301
|
+
// Explicit config path provided
|
|
302
|
+
try {
|
|
303
|
+
mcpConfig = loadMCPConfigurationFromPath(this.mcpConfigPath);
|
|
304
|
+
if (this.debug) {
|
|
305
|
+
console.log(`[DEBUG] Loaded MCP config from: ${this.mcpConfigPath}`);
|
|
306
|
+
}
|
|
307
|
+
} catch (error) {
|
|
308
|
+
throw new Error(`Failed to load MCP config from ${this.mcpConfigPath}: ${error.message}`);
|
|
309
|
+
}
|
|
310
|
+
} else if (this.mcpServers) {
|
|
311
|
+
// Backward compatibility: convert old mcpServers format
|
|
312
|
+
mcpConfig = { mcpServers: this.mcpServers };
|
|
313
|
+
if (this.debug) {
|
|
314
|
+
console.warn('[DEBUG] Using deprecated mcpServers option. Consider using mcpConfig instead.');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Note: auto-discovery fallback is removed - user must explicitly provide config
|
|
318
|
+
|
|
319
|
+
// Initialize the MCP XML bridge
|
|
320
|
+
this.mcpBridge = new MCPXmlBridge({ debug: this.debug });
|
|
321
|
+
await this.mcpBridge.initialize(mcpConfig);
|
|
322
|
+
|
|
323
|
+
const mcpToolCount = this.mcpBridge.getToolNames().length;
|
|
324
|
+
if (mcpToolCount > 0) {
|
|
325
|
+
if (this.debug) {
|
|
326
|
+
console.log(`[DEBUG] Loaded ${mcpToolCount} MCP tools`);
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
// For backward compatibility: if no tools were loaded, set bridge to null
|
|
330
|
+
// This maintains the behavior expected by existing tests
|
|
331
|
+
if (this.debug) {
|
|
332
|
+
console.log('[DEBUG] No MCP tools loaded, setting bridge to null');
|
|
333
|
+
}
|
|
334
|
+
this.mcpBridge = null;
|
|
335
|
+
}
|
|
336
|
+
} catch (error) {
|
|
337
|
+
console.error('[MCP] Error initializing MCP:', error);
|
|
338
|
+
this.mcpBridge = null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
240
342
|
/**
|
|
241
343
|
* Get the system message with instructions for the AI (XML Tool Format)
|
|
242
344
|
*/
|
|
@@ -428,6 +530,13 @@ When troubleshooting:
|
|
|
428
530
|
// Add Tool Definitions
|
|
429
531
|
systemMessage += `\n# Tools Available\n${toolDefinitions}\n`;
|
|
430
532
|
|
|
533
|
+
// Add MCP tools if available
|
|
534
|
+
if (this.mcpBridge && this.mcpBridge.getToolNames().length > 0) {
|
|
535
|
+
systemMessage += `\n## MCP Tools (JSON parameters in <params> tag)\n`;
|
|
536
|
+
systemMessage += this.mcpBridge.getXmlToolDefinitions();
|
|
537
|
+
systemMessage += `\n\nFor MCP tools, use JSON format within the params tag, e.g.:\n<mcp_tool>\n<params>\n{"key": "value"}\n</params>\n</mcp_tool>\n`;
|
|
538
|
+
}
|
|
539
|
+
|
|
431
540
|
// Add folder information
|
|
432
541
|
const searchDirectory = this.allowedFolders.length > 0 ? this.allowedFolders[0] : process.cwd();
|
|
433
542
|
if (this.debug) {
|
|
@@ -640,7 +749,11 @@ When troubleshooting:
|
|
|
640
749
|
validTools.push('implement');
|
|
641
750
|
}
|
|
642
751
|
|
|
643
|
-
|
|
752
|
+
// Try parsing with hybrid parser that supports both native and MCP tools
|
|
753
|
+
const nativeTools = validTools;
|
|
754
|
+
const parsedTool = this.mcpBridge
|
|
755
|
+
? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge)
|
|
756
|
+
: parseXmlToolCallWithThinking(assistantResponseContent, validTools);
|
|
644
757
|
if (parsedTool) {
|
|
645
758
|
const { toolName, params } = parsedTool;
|
|
646
759
|
if (this.debug) console.log(`[DEBUG] Parsed tool call: ${toolName} with params:`, params);
|
|
@@ -654,7 +767,9 @@ When troubleshooting:
|
|
|
654
767
|
const lastAssistantMessage = [...currentMessages].reverse().find(msg =>
|
|
655
768
|
msg.role === 'assistant' &&
|
|
656
769
|
msg.content &&
|
|
657
|
-
!
|
|
770
|
+
!(this.mcpBridge
|
|
771
|
+
? parseHybridXmlToolCall(msg.content, validTools, this.mcpBridge)
|
|
772
|
+
: parseXmlToolCallWithThinking(msg.content, validTools))
|
|
658
773
|
);
|
|
659
774
|
|
|
660
775
|
if (lastAssistantMessage) {
|
|
@@ -677,8 +792,32 @@ When troubleshooting:
|
|
|
677
792
|
}
|
|
678
793
|
break;
|
|
679
794
|
} else {
|
|
680
|
-
//
|
|
681
|
-
|
|
795
|
+
// Check tool type and execute accordingly
|
|
796
|
+
const { type } = parsedTool;
|
|
797
|
+
|
|
798
|
+
if (type === 'mcp' && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
799
|
+
// Execute MCP tool
|
|
800
|
+
try {
|
|
801
|
+
if (this.debug) console.log(`[DEBUG] Executing MCP tool '${toolName}' with params:`, params);
|
|
802
|
+
|
|
803
|
+
// Execute MCP tool through the bridge
|
|
804
|
+
const executionResult = await this.mcpBridge.mcpTools[toolName].execute(params);
|
|
805
|
+
|
|
806
|
+
const toolResultContent = typeof executionResult === 'string' ? executionResult : JSON.stringify(executionResult, null, 2);
|
|
807
|
+
const preview = createMessagePreview(toolResultContent);
|
|
808
|
+
if (this.debug) {
|
|
809
|
+
console.log(`[DEBUG] MCP tool '${toolName}' executed successfully. Result preview: ${preview}`);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
currentMessages.push({ role: 'user', content: `<tool_result>\n${toolResultContent}\n</tool_result>` });
|
|
813
|
+
} catch (error) {
|
|
814
|
+
console.error(`Error executing MCP tool ${toolName}:`, error);
|
|
815
|
+
const toolResultContent = `Error executing MCP tool ${toolName}: ${error.message}`;
|
|
816
|
+
if (this.debug) console.log(`[DEBUG] MCP tool '${toolName}' execution FAILED.`);
|
|
817
|
+
currentMessages.push({ role: 'user', content: `<tool_result>\n${toolResultContent}\n</tool_result>` });
|
|
818
|
+
}
|
|
819
|
+
} else if (this.toolImplementations[toolName]) {
|
|
820
|
+
// Execute native tool
|
|
682
821
|
try {
|
|
683
822
|
// Add sessionId to params for tool execution
|
|
684
823
|
const toolParams = { ...params, sessionId: this.sessionId };
|
|
@@ -778,9 +917,15 @@ When troubleshooting:
|
|
|
778
917
|
} else {
|
|
779
918
|
console.error(`[ERROR] Unknown tool: ${toolName}`);
|
|
780
919
|
currentMessages.push({ role: 'assistant', content: assistantResponseContent });
|
|
920
|
+
|
|
921
|
+
// Build list of available tools including MCP tools
|
|
922
|
+
const nativeTools = Object.keys(this.toolImplementations);
|
|
923
|
+
const mcpTools = this.mcpBridge ? this.mcpBridge.getToolNames() : [];
|
|
924
|
+
const allAvailableTools = [...nativeTools, ...mcpTools];
|
|
925
|
+
|
|
781
926
|
currentMessages.push({
|
|
782
927
|
role: 'user',
|
|
783
|
-
content: `<tool_result>\nError: Unknown tool '${toolName}'. Available tools: ${
|
|
928
|
+
content: `<tool_result>\nError: Unknown tool '${toolName}'. Available tools: ${allAvailableTools.join(', ')}\n</tool_result>`
|
|
784
929
|
});
|
|
785
930
|
}
|
|
786
931
|
}
|
|
@@ -1309,6 +1454,26 @@ Convert your previous response content into actual JSON data that follows this s
|
|
|
1309
1454
|
}
|
|
1310
1455
|
}
|
|
1311
1456
|
|
|
1457
|
+
/**
|
|
1458
|
+
* Clean up resources (including MCP connections)
|
|
1459
|
+
*/
|
|
1460
|
+
async cleanup() {
|
|
1461
|
+
// Clean up MCP bridge
|
|
1462
|
+
if (this.mcpBridge) {
|
|
1463
|
+
try {
|
|
1464
|
+
await this.mcpBridge.cleanup();
|
|
1465
|
+
if (this.debug) {
|
|
1466
|
+
console.log('[DEBUG] MCP bridge cleaned up');
|
|
1467
|
+
}
|
|
1468
|
+
} catch (error) {
|
|
1469
|
+
console.error('Error cleaning up MCP bridge:', error);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
// Clear history and other resources
|
|
1474
|
+
this.clearHistory();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1312
1477
|
/**
|
|
1313
1478
|
* Cancel the current request
|
|
1314
1479
|
*/
|
package/build/agent/acp/tools.js
CHANGED
|
@@ -269,7 +269,7 @@ export class ACPToolManager {
|
|
|
269
269
|
name: 'search',
|
|
270
270
|
description: 'Search for code patterns and content using flexible text search with stemming and stopword removal. Supports regex patterns and elastic search query syntax.',
|
|
271
271
|
kind: ToolCallKind.search,
|
|
272
|
-
|
|
272
|
+
inputSchema: {
|
|
273
273
|
type: 'object',
|
|
274
274
|
properties: {
|
|
275
275
|
query: {
|
|
@@ -296,7 +296,7 @@ export class ACPToolManager {
|
|
|
296
296
|
name: 'query',
|
|
297
297
|
description: 'Perform structural queries using AST patterns to find specific code structures like functions, classes, or methods.',
|
|
298
298
|
kind: ToolCallKind.query,
|
|
299
|
-
|
|
299
|
+
inputSchema: {
|
|
300
300
|
type: 'object',
|
|
301
301
|
properties: {
|
|
302
302
|
pattern: {
|
|
@@ -323,7 +323,7 @@ export class ACPToolManager {
|
|
|
323
323
|
name: 'extract',
|
|
324
324
|
description: 'Extract specific code blocks from files based on file paths and optional line numbers.',
|
|
325
325
|
kind: ToolCallKind.extract,
|
|
326
|
-
|
|
326
|
+
inputSchema: {
|
|
327
327
|
type: 'object',
|
|
328
328
|
properties: {
|
|
329
329
|
files: {
|
|
@@ -352,7 +352,7 @@ export class ACPToolManager {
|
|
|
352
352
|
name: 'delegate',
|
|
353
353
|
description: 'Automatically delegate big distinct tasks to specialized probe subagents within the agentic loop. Use when complex requests can be broken into focused, parallel tasks.',
|
|
354
354
|
kind: ToolCallKind.execute,
|
|
355
|
-
|
|
355
|
+
inputSchema: {
|
|
356
356
|
type: 'object',
|
|
357
357
|
properties: {
|
|
358
358
|
task: {
|
|
@@ -288,26 +288,26 @@ describe('ACPToolManager', () => {
|
|
|
288
288
|
const searchTool = definitions.find(d => d.name === 'search');
|
|
289
289
|
expect(searchTool).toBeDefined();
|
|
290
290
|
expect(searchTool.kind).toBe(ToolCallKind.search);
|
|
291
|
-
expect(searchTool.
|
|
292
|
-
expect(searchTool.
|
|
293
|
-
|
|
291
|
+
expect(searchTool.inputSchema.properties.query).toBeDefined();
|
|
292
|
+
expect(searchTool.inputSchema.required).toContain('query');
|
|
293
|
+
|
|
294
294
|
const queryTool = definitions.find(d => d.name === 'query');
|
|
295
295
|
expect(queryTool).toBeDefined();
|
|
296
296
|
expect(queryTool.kind).toBe(ToolCallKind.query);
|
|
297
|
-
expect(queryTool.
|
|
298
|
-
expect(queryTool.
|
|
299
|
-
|
|
297
|
+
expect(queryTool.inputSchema.properties.pattern).toBeDefined();
|
|
298
|
+
expect(queryTool.inputSchema.required).toContain('pattern');
|
|
299
|
+
|
|
300
300
|
const extractTool = definitions.find(d => d.name === 'extract');
|
|
301
301
|
expect(extractTool).toBeDefined();
|
|
302
302
|
expect(extractTool.kind).toBe(ToolCallKind.extract);
|
|
303
|
-
expect(extractTool.
|
|
304
|
-
expect(extractTool.
|
|
305
|
-
|
|
303
|
+
expect(extractTool.inputSchema.properties.files).toBeDefined();
|
|
304
|
+
expect(extractTool.inputSchema.required).toContain('files');
|
|
305
|
+
|
|
306
306
|
const delegateTool = definitions.find(d => d.name === 'delegate');
|
|
307
307
|
expect(delegateTool).toBeDefined();
|
|
308
308
|
expect(delegateTool.kind).toBe(ToolCallKind.execute);
|
|
309
|
-
expect(delegateTool.
|
|
310
|
-
expect(delegateTool.
|
|
309
|
+
expect(delegateTool.inputSchema.properties.task).toBeDefined();
|
|
310
|
+
expect(delegateTool.inputSchema.required).toContain('task');
|
|
311
311
|
});
|
|
312
312
|
});
|
|
313
313
|
|