@probelabs/probe 0.6.0-rc118 → 0.6.0-rc120
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/build/agent/ProbeAgent.js +85 -10
- package/build/agent/acp/server.js +11 -6
- package/build/agent/index.js +2447 -147
- package/build/agent/mcp/client.js +17 -3
- package/build/agent/schemaUtils.js +7 -4
- package/cjs/agent/ProbeAgent.cjs +2437 -143
- package/cjs/index.cjs +2437 -143
- package/package.json +2 -2
- package/src/agent/ProbeAgent.js +85 -10
- package/src/agent/acp/server.js +11 -6
- package/src/agent/index.js +5 -1
- package/src/agent/mcp/client.js +17 -3
- package/src/agent/schemaUtils.js +7 -4
|
@@ -8,7 +8,7 @@ import { randomUUID } from 'crypto';
|
|
|
8
8
|
import { EventEmitter } from 'events';
|
|
9
9
|
import { existsSync } from 'fs';
|
|
10
10
|
import { readFile, stat } from 'fs/promises';
|
|
11
|
-
import { resolve, isAbsolute } from 'path';
|
|
11
|
+
import { resolve, isAbsolute, dirname } from 'path';
|
|
12
12
|
import { TokenCounter } from './tokenCounter.js';
|
|
13
13
|
import {
|
|
14
14
|
createTools,
|
|
@@ -145,12 +145,48 @@ export class ProbeAgent {
|
|
|
145
145
|
// Initialize the AI model
|
|
146
146
|
this.initializeModel();
|
|
147
147
|
|
|
148
|
+
// Note: MCP initialization is now done in initialize() method
|
|
149
|
+
// Constructor must remain synchronous for backward compatibility
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Initialize the agent asynchronously (must be called after constructor)
|
|
154
|
+
* This method initializes MCP and merges MCP tools into the tool list
|
|
155
|
+
*/
|
|
156
|
+
async initialize() {
|
|
148
157
|
// Initialize MCP if enabled
|
|
149
158
|
if (this.enableMcp) {
|
|
150
|
-
|
|
159
|
+
try {
|
|
160
|
+
await this.initializeMCP();
|
|
161
|
+
|
|
162
|
+
// Merge MCP tools into toolImplementations for unified access
|
|
163
|
+
if (this.mcpBridge) {
|
|
164
|
+
const mcpTools = this.mcpBridge.mcpTools || {};
|
|
165
|
+
for (const [toolName, toolImpl] of Object.entries(mcpTools)) {
|
|
166
|
+
this.toolImplementations[toolName] = toolImpl;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Log all available tools after MCP initialization
|
|
171
|
+
if (this.debug) {
|
|
172
|
+
const allToolNames = Object.keys(this.toolImplementations);
|
|
173
|
+
const nativeToolCount = allToolNames.filter(name => !this.mcpBridge?.mcpTools?.[name]).length;
|
|
174
|
+
const mcpToolCount = allToolNames.length - nativeToolCount;
|
|
175
|
+
|
|
176
|
+
console.error('\n[DEBUG] ========================================');
|
|
177
|
+
console.error('[DEBUG] All Tools Initialized');
|
|
178
|
+
console.error(`[DEBUG] Native tools: ${nativeToolCount}, MCP tools: ${mcpToolCount}`);
|
|
179
|
+
console.error('[DEBUG] Available tools:');
|
|
180
|
+
for (const toolName of allToolNames) {
|
|
181
|
+
const isMCP = this.mcpBridge?.mcpTools?.[toolName] ? ' (MCP)' : '';
|
|
182
|
+
console.error(`[DEBUG] - ${toolName}${isMCP}`);
|
|
183
|
+
}
|
|
184
|
+
console.error('[DEBUG] ========================================\n');
|
|
185
|
+
}
|
|
186
|
+
} catch (error) {
|
|
151
187
|
console.error('[MCP] Failed to initialize MCP:', error);
|
|
152
188
|
this.mcpBridge = null;
|
|
153
|
-
}
|
|
189
|
+
}
|
|
154
190
|
}
|
|
155
191
|
}
|
|
156
192
|
|
|
@@ -442,23 +478,62 @@ export class ProbeAgent {
|
|
|
442
478
|
}
|
|
443
479
|
|
|
444
480
|
/**
|
|
445
|
-
* Extract directory paths from listFiles tool
|
|
481
|
+
* Extract directory paths from tool output (both listFiles and extract tool)
|
|
446
482
|
* @param {string} content - Tool output content
|
|
447
483
|
* @returns {string[]} - Array of directory paths
|
|
448
484
|
*/
|
|
449
485
|
extractListFilesDirectories(content) {
|
|
450
486
|
const directories = [];
|
|
451
487
|
|
|
452
|
-
// Pattern
|
|
453
|
-
|
|
488
|
+
// Pattern 1: Extract directory from extract tool "File:" header
|
|
489
|
+
// Format: "File: /path/to/file.md" or "File: ./relative/path/file.md"
|
|
490
|
+
const fileHeaderPattern = /^File:\s+(.+)$/gm;
|
|
454
491
|
|
|
455
492
|
let match;
|
|
493
|
+
while ((match = fileHeaderPattern.exec(content)) !== null) {
|
|
494
|
+
const filePath = match[1].trim();
|
|
495
|
+
// Get directory from file path
|
|
496
|
+
const dir = dirname(filePath);
|
|
497
|
+
if (dir && dir !== '.') {
|
|
498
|
+
directories.push(dir);
|
|
499
|
+
if (this.debug) {
|
|
500
|
+
console.log(`[DEBUG] Extracted directory context from File header: ${dir}`);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Pattern 2: Extract directory from listFiles output format: "/path/to/directory:"
|
|
506
|
+
// Matches absolute paths (/path/to/dir:) or current directory markers (.:) or Windows paths (C:\path:) at start of line
|
|
507
|
+
// Very strict to avoid matching random text like ".Something:" or "./Some text:"
|
|
508
|
+
const dirPattern = /^(\/[^\n:]+|[A-Z]:\\[^\n:]+|\.\.?(?:\/[^\n:]+)?):\s*$/gm;
|
|
509
|
+
|
|
456
510
|
while ((match = dirPattern.exec(content)) !== null) {
|
|
457
511
|
const dirPath = match[1].trim();
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
512
|
+
|
|
513
|
+
// Strict validation: must look like an actual filesystem path
|
|
514
|
+
// Reject if contains spaces or other characters that wouldn't be in listFiles output
|
|
515
|
+
const hasInvalidChars = /\s/.test(dirPath); // Contains whitespace
|
|
516
|
+
|
|
517
|
+
// Validate this looks like an actual path, not random text
|
|
518
|
+
// Must be either: absolute path (Unix or Windows), or ./ or ../ followed by valid path chars
|
|
519
|
+
const isValidPath = (
|
|
520
|
+
!hasInvalidChars && (
|
|
521
|
+
dirPath.startsWith('/') || // Unix absolute path
|
|
522
|
+
/^[A-Z]:\\/.test(dirPath) || // Windows absolute path (C:\)
|
|
523
|
+
dirPath === '.' || // Current directory
|
|
524
|
+
dirPath === '..' || // Parent directory
|
|
525
|
+
(dirPath.startsWith('./') && dirPath.length > 2 && !dirPath.includes(' ')) || // ./something (no spaces)
|
|
526
|
+
(dirPath.startsWith('../') && dirPath.length > 3 && !dirPath.includes(' ')) // ../something (no spaces)
|
|
527
|
+
)
|
|
528
|
+
);
|
|
529
|
+
|
|
530
|
+
if (isValidPath) {
|
|
531
|
+
// Avoid duplicates
|
|
532
|
+
if (!directories.includes(dirPath)) {
|
|
533
|
+
directories.push(dirPath);
|
|
534
|
+
if (this.debug) {
|
|
535
|
+
console.log(`[DEBUG] Extracted directory context from listFiles: ${dirPath}`);
|
|
536
|
+
}
|
|
462
537
|
}
|
|
463
538
|
}
|
|
464
539
|
}
|
|
@@ -31,12 +31,14 @@ class ACPSession {
|
|
|
31
31
|
/**
|
|
32
32
|
* Get or create ProbeAgent for this session
|
|
33
33
|
*/
|
|
34
|
-
getAgent(config = {}) {
|
|
34
|
+
async getAgent(config = {}) {
|
|
35
35
|
if (!this.agent) {
|
|
36
36
|
this.agent = new ProbeAgent({
|
|
37
37
|
sessionId: this.id,
|
|
38
38
|
...config
|
|
39
39
|
});
|
|
40
|
+
// Initialize MCP if enabled
|
|
41
|
+
await this.agent.initialize();
|
|
40
42
|
}
|
|
41
43
|
return this.agent;
|
|
42
44
|
}
|
|
@@ -320,20 +322,23 @@ export class ACPServer {
|
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
session.touch();
|
|
323
|
-
|
|
325
|
+
|
|
324
326
|
// Get or create ProbeAgent for this session
|
|
325
|
-
const agent = session.getAgent({
|
|
327
|
+
const agent = await session.getAgent({
|
|
326
328
|
path: this.options.path,
|
|
327
329
|
provider: this.options.provider,
|
|
328
330
|
model: this.options.model,
|
|
329
331
|
allowEdit: this.options.allowEdit,
|
|
330
|
-
debug: this.options.debug
|
|
332
|
+
debug: this.options.debug,
|
|
333
|
+
enableMcp: this.options.enableMcp,
|
|
334
|
+
mcpConfig: this.options.mcpConfig,
|
|
335
|
+
mcpConfigPath: this.options.mcpConfigPath
|
|
331
336
|
});
|
|
332
|
-
|
|
337
|
+
|
|
333
338
|
if (this.options.debug) {
|
|
334
339
|
console.error(`[ACP] Processing prompt for session ${params.sessionId}:`, params.message.substring(0, 100));
|
|
335
340
|
}
|
|
336
|
-
|
|
341
|
+
|
|
337
342
|
try {
|
|
338
343
|
// Process the message with the ProbeAgent
|
|
339
344
|
const response = await agent.answer(params.message);
|