@probelabs/probe 0.6.0-rc100
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/README.md +583 -0
- package/bin/.gitkeep +0 -0
- package/bin/probe +158 -0
- package/bin/probe-binary +0 -0
- package/build/agent/ProbeAgent.d.ts +199 -0
- package/build/agent/ProbeAgent.js +1486 -0
- package/build/agent/acp/README.md +347 -0
- package/build/agent/acp/connection.js +237 -0
- package/build/agent/acp/connection.test.js +311 -0
- package/build/agent/acp/examples/simple-client.js +212 -0
- package/build/agent/acp/examples/tool-lifecycle.js +230 -0
- package/build/agent/acp/final-test.js +173 -0
- package/build/agent/acp/index.js +5 -0
- package/build/agent/acp/integration.test.js +385 -0
- package/build/agent/acp/manual-test.js +410 -0
- package/build/agent/acp/protocol-test.js +190 -0
- package/build/agent/acp/server.js +448 -0
- package/build/agent/acp/server.test.js +371 -0
- package/build/agent/acp/test-runner.js +216 -0
- package/build/agent/acp/test-utils/README.md +315 -0
- package/build/agent/acp/test-utils/acp-tester.js +484 -0
- package/build/agent/acp/test-utils/mock-acp-client.js +434 -0
- package/build/agent/acp/tools.js +368 -0
- package/build/agent/acp/tools.test.js +334 -0
- package/build/agent/acp/types.js +218 -0
- package/build/agent/acp/types.test.js +327 -0
- package/build/agent/appTracer.js +360 -0
- package/build/agent/fileSpanExporter.js +169 -0
- package/build/agent/index.js +7426 -0
- 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/probeTool.js +257 -0
- package/build/agent/schemaUtils.js +1726 -0
- package/build/agent/simpleTelemetry.js +267 -0
- package/build/agent/telemetry.js +225 -0
- package/build/agent/tokenCounter.js +395 -0
- package/build/agent/tools.js +163 -0
- package/build/cli.js +49 -0
- package/build/delegate.js +267 -0
- package/build/directory-resolver.js +237 -0
- package/build/downloader.js +750 -0
- package/build/extract.js +149 -0
- package/build/index.js +70 -0
- package/build/mcp/index.js +514 -0
- package/build/mcp/index.ts +608 -0
- package/build/query.js +116 -0
- package/build/search.js +247 -0
- package/build/tools/common.js +410 -0
- package/build/tools/index.js +40 -0
- package/build/tools/langchain.js +88 -0
- package/build/tools/system-message.js +121 -0
- package/build/tools/vercel.js +271 -0
- package/build/utils/file-lister.js +193 -0
- package/build/utils.js +128 -0
- package/cjs/agent/ProbeAgent.cjs +5829 -0
- package/cjs/index.cjs +6217 -0
- package/cjs/package.json +3 -0
- package/index.d.ts +401 -0
- package/package.json +114 -0
- package/scripts/postinstall.js +172 -0
- package/src/agent/ProbeAgent.d.ts +199 -0
- package/src/agent/ProbeAgent.js +1486 -0
- package/src/agent/acp/README.md +347 -0
- package/src/agent/acp/connection.js +237 -0
- package/src/agent/acp/connection.test.js +311 -0
- package/src/agent/acp/examples/simple-client.js +212 -0
- package/src/agent/acp/examples/tool-lifecycle.js +230 -0
- package/src/agent/acp/final-test.js +173 -0
- package/src/agent/acp/index.js +5 -0
- package/src/agent/acp/integration.test.js +385 -0
- package/src/agent/acp/manual-test.js +410 -0
- package/src/agent/acp/protocol-test.js +190 -0
- package/src/agent/acp/server.js +448 -0
- package/src/agent/acp/server.test.js +371 -0
- package/src/agent/acp/test-runner.js +216 -0
- package/src/agent/acp/test-utils/README.md +315 -0
- package/src/agent/acp/test-utils/acp-tester.js +484 -0
- package/src/agent/acp/test-utils/mock-acp-client.js +434 -0
- package/src/agent/acp/tools.js +368 -0
- package/src/agent/acp/tools.test.js +334 -0
- package/src/agent/acp/types.js +218 -0
- package/src/agent/acp/types.test.js +327 -0
- package/src/agent/appTracer.js +360 -0
- package/src/agent/fileSpanExporter.js +169 -0
- package/src/agent/index.js +813 -0
- 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/probeTool.js +257 -0
- package/src/agent/schemaUtils.js +1726 -0
- package/src/agent/simpleTelemetry.js +267 -0
- package/src/agent/telemetry.js +225 -0
- package/src/agent/tokenCounter.js +395 -0
- package/src/agent/tools.js +163 -0
- package/src/cli.js +49 -0
- package/src/delegate.js +267 -0
- package/src/directory-resolver.js +237 -0
- package/src/downloader.js +750 -0
- package/src/extract.js +149 -0
- package/src/index.js +70 -0
- package/src/mcp/index.ts +608 -0
- package/src/query.js +116 -0
- package/src/search.js +247 -0
- package/src/tools/common.js +410 -0
- package/src/tools/index.js +40 -0
- package/src/tools/langchain.js +88 -0
- package/src/tools/system-message.js +121 -0
- package/src/tools/vercel.js +271 -0
- package/src/utils/file-lister.js +193 -0
- package/src/utils.js +128 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XML-to-MCP Bridge
|
|
3
|
+
* Allows using MCP tools with XML-like syntax while maintaining JSON parameters
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { MCPClientManager } from './client.js';
|
|
7
|
+
import { loadMCPConfiguration } from './config.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Convert MCP tool to XML definition format
|
|
11
|
+
* @param {string} name - Tool name
|
|
12
|
+
* @param {Object} tool - MCP tool object
|
|
13
|
+
* @returns {string} XML-formatted tool definition
|
|
14
|
+
*/
|
|
15
|
+
export function mcpToolToXmlDefinition(name, tool) {
|
|
16
|
+
const description = tool.description || 'MCP tool';
|
|
17
|
+
const inputSchema = tool.inputSchema || tool.parameters || {};
|
|
18
|
+
|
|
19
|
+
// Build parameter documentation
|
|
20
|
+
let paramDocs = '';
|
|
21
|
+
if (inputSchema.properties) {
|
|
22
|
+
paramDocs = '\n\nParameters (provide as JSON object):';
|
|
23
|
+
for (const [paramName, paramSchema] of Object.entries(inputSchema.properties)) {
|
|
24
|
+
const required = inputSchema.required?.includes(paramName) ? ' (required)' : ' (optional)';
|
|
25
|
+
const desc = paramSchema.description || '';
|
|
26
|
+
const type = paramSchema.type || 'any';
|
|
27
|
+
paramDocs += `\n- ${paramName}: ${type}${required} - ${desc}`;
|
|
28
|
+
|
|
29
|
+
if (paramSchema.enum) {
|
|
30
|
+
paramDocs += ` [choices: ${paramSchema.enum.join(', ')}]`;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return `## ${name}
|
|
36
|
+
Description: ${description}${paramDocs}
|
|
37
|
+
|
|
38
|
+
Usage:
|
|
39
|
+
<${name}>
|
|
40
|
+
<params>
|
|
41
|
+
{
|
|
42
|
+
"param1": "value1",
|
|
43
|
+
"param2": "value2"
|
|
44
|
+
}
|
|
45
|
+
</params>
|
|
46
|
+
</${name}>
|
|
47
|
+
|
|
48
|
+
Or for simple single parameter:
|
|
49
|
+
<${name}>
|
|
50
|
+
<params>value</params>
|
|
51
|
+
</${name}>`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Parse XML tool call with JSON parameters
|
|
56
|
+
* Handles both JSON object parameters and simple string parameters
|
|
57
|
+
* @param {string} xmlString - XML string containing tool call
|
|
58
|
+
* @param {Array<string>} mcpToolNames - List of available MCP tool names
|
|
59
|
+
* @returns {Object|null} Parsed tool call with name and params
|
|
60
|
+
*/
|
|
61
|
+
export function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
|
|
62
|
+
// Clean the XML string
|
|
63
|
+
const cleanedXml = xmlString.replace(/<thinking>[\s\S]*?<\/thinking>/g, '').trim();
|
|
64
|
+
|
|
65
|
+
for (const toolName of mcpToolNames) {
|
|
66
|
+
// Look for the tool in XML format
|
|
67
|
+
const openTag = `<${toolName}>`;
|
|
68
|
+
const closeTag = `</${toolName}>`;
|
|
69
|
+
|
|
70
|
+
const openIndex = cleanedXml.indexOf(openTag);
|
|
71
|
+
if (openIndex === -1) continue;
|
|
72
|
+
|
|
73
|
+
const closeIndex = cleanedXml.indexOf(closeTag, openIndex);
|
|
74
|
+
if (closeIndex === -1) continue;
|
|
75
|
+
|
|
76
|
+
// Extract content between tags
|
|
77
|
+
const contentStart = openIndex + openTag.length;
|
|
78
|
+
const content = cleanedXml.substring(contentStart, closeIndex).trim();
|
|
79
|
+
|
|
80
|
+
// Look for params tag
|
|
81
|
+
const paramsMatch = content.match(/<params>([\s\S]*?)<\/params>/);
|
|
82
|
+
|
|
83
|
+
let params = {};
|
|
84
|
+
if (paramsMatch) {
|
|
85
|
+
let paramsContent = paramsMatch[1].trim();
|
|
86
|
+
|
|
87
|
+
// Handle CDATA sections
|
|
88
|
+
const cdataMatch = paramsContent.match(/^<!\[CDATA\[([\s\S]*?)\]\]>$/);
|
|
89
|
+
if (cdataMatch) {
|
|
90
|
+
paramsContent = cdataMatch[1];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Try to parse as JSON first
|
|
94
|
+
try {
|
|
95
|
+
// Handle JSON object
|
|
96
|
+
if (paramsContent.startsWith('{')) {
|
|
97
|
+
params = JSON.parse(paramsContent);
|
|
98
|
+
} else {
|
|
99
|
+
// Handle simple string parameter
|
|
100
|
+
// For backwards compatibility with simple XML params
|
|
101
|
+
params = { value: paramsContent };
|
|
102
|
+
}
|
|
103
|
+
} catch (e) {
|
|
104
|
+
// If JSON parsing fails, treat as simple string
|
|
105
|
+
params = { value: paramsContent };
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
// Legacy format: parse individual XML parameters
|
|
109
|
+
const paramPattern = /<(\w+)>([\s\S]*?)<\/\1>/g;
|
|
110
|
+
let match;
|
|
111
|
+
while ((match = paramPattern.exec(content)) !== null) {
|
|
112
|
+
const [, paramName, paramValue] = match;
|
|
113
|
+
params[paramName] = paramValue.trim();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { toolName, params };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* MCP Tool Manager that bridges XML and MCP
|
|
125
|
+
*/
|
|
126
|
+
export class MCPXmlBridge {
|
|
127
|
+
constructor(options = {}) {
|
|
128
|
+
this.debug = options.debug || false;
|
|
129
|
+
this.mcpTools = {};
|
|
130
|
+
this.mcpManager = null;
|
|
131
|
+
this.xmlDefinitions = {};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Initialize MCP connections and load tools
|
|
136
|
+
* @param {Object|Array<Object>} config - MCP configuration object or server configurations (deprecated)
|
|
137
|
+
*/
|
|
138
|
+
async initialize(config = null) {
|
|
139
|
+
let mcpConfigs = null;
|
|
140
|
+
|
|
141
|
+
if (!config) {
|
|
142
|
+
// No config provided - fall back to auto-discovery for backward compatibility
|
|
143
|
+
mcpConfigs = loadMCPConfiguration();
|
|
144
|
+
} else if (Array.isArray(config)) {
|
|
145
|
+
// Deprecated: Array of server configs (backward compatibility)
|
|
146
|
+
mcpConfigs = { mcpServers: config };
|
|
147
|
+
} else {
|
|
148
|
+
// New: Full config object provided directly
|
|
149
|
+
mcpConfigs = config;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!mcpConfigs || !mcpConfigs.mcpServers || Object.keys(mcpConfigs.mcpServers).length === 0) {
|
|
153
|
+
if (this.debug) {
|
|
154
|
+
console.error('[MCP] No MCP servers configured');
|
|
155
|
+
}
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// Initialize the MCP client manager
|
|
161
|
+
this.mcpManager = new MCPClientManager({ debug: this.debug });
|
|
162
|
+
const result = await this.mcpManager.initialize(mcpConfigs);
|
|
163
|
+
|
|
164
|
+
// Get tools from the manager
|
|
165
|
+
const vercelTools = this.mcpManager.getVercelTools();
|
|
166
|
+
this.mcpTools = vercelTools;
|
|
167
|
+
|
|
168
|
+
// Generate XML definitions for all tools
|
|
169
|
+
for (const [name, tool] of Object.entries(vercelTools)) {
|
|
170
|
+
this.xmlDefinitions[name] = mcpToolToXmlDefinition(name, tool);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (this.debug) {
|
|
174
|
+
console.error(`[MCP] Loaded ${Object.keys(vercelTools).length} MCP tools from ${result.connected} server(s)`);
|
|
175
|
+
}
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.error('[MCP] Failed to initialize MCP connections:', error);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Get all XML tool definitions for inclusion in system prompt
|
|
183
|
+
* @returns {string} Combined XML tool definitions
|
|
184
|
+
*/
|
|
185
|
+
getXmlToolDefinitions() {
|
|
186
|
+
return Object.values(this.xmlDefinitions).join('\n\n');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Get list of MCP tool names
|
|
191
|
+
* @returns {Array<string>} Tool names
|
|
192
|
+
*/
|
|
193
|
+
getToolNames() {
|
|
194
|
+
return Object.keys(this.mcpTools);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Execute an MCP tool from XML call
|
|
199
|
+
* @param {string} xmlString - XML tool call string
|
|
200
|
+
* @returns {Promise<Object>} Tool execution result
|
|
201
|
+
*/
|
|
202
|
+
async executeFromXml(xmlString) {
|
|
203
|
+
const parsed = parseXmlMcpToolCall(xmlString, this.getToolNames());
|
|
204
|
+
|
|
205
|
+
if (!parsed) {
|
|
206
|
+
throw new Error('No valid MCP tool call found in XML');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const { toolName, params } = parsed;
|
|
210
|
+
|
|
211
|
+
if (this.debug) {
|
|
212
|
+
console.error(`[MCP] Executing MCP tool: ${toolName} with params:`, params);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const tool = this.mcpTools[toolName];
|
|
216
|
+
if (!tool) {
|
|
217
|
+
throw new Error(`Unknown MCP tool: ${toolName}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
try {
|
|
221
|
+
const result = await tool.execute(params);
|
|
222
|
+
return {
|
|
223
|
+
success: true,
|
|
224
|
+
toolName,
|
|
225
|
+
result
|
|
226
|
+
};
|
|
227
|
+
} catch (error) {
|
|
228
|
+
return {
|
|
229
|
+
success: false,
|
|
230
|
+
toolName,
|
|
231
|
+
error: error.message
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Check if a tool call is an MCP tool
|
|
238
|
+
* @param {string} toolName - Tool name to check
|
|
239
|
+
* @returns {boolean} True if it's an MCP tool
|
|
240
|
+
*/
|
|
241
|
+
isMcpTool(toolName) {
|
|
242
|
+
return toolName in this.mcpTools;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Clean up MCP connections
|
|
247
|
+
*/
|
|
248
|
+
async cleanup() {
|
|
249
|
+
if (this.mcpManager) {
|
|
250
|
+
await this.mcpManager.disconnect();
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Enhanced XML parser that handles both native and MCP tools
|
|
257
|
+
* @param {string} xmlString - XML string to parse
|
|
258
|
+
* @param {Array<string>} nativeTools - List of native tool names
|
|
259
|
+
* @param {MCPXmlBridge} mcpBridge - MCP bridge instance
|
|
260
|
+
* @returns {Object|null} Parsed tool call
|
|
261
|
+
*/
|
|
262
|
+
export function parseHybridXmlToolCall(xmlString, nativeTools = [], mcpBridge = null) {
|
|
263
|
+
// First try native tools with standard XML parsing
|
|
264
|
+
for (const toolName of nativeTools) {
|
|
265
|
+
const nativeResult = parseNativeXmlTool(xmlString, toolName);
|
|
266
|
+
if (nativeResult) {
|
|
267
|
+
return { ...nativeResult, type: 'native' };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Then try MCP tools if bridge is available
|
|
272
|
+
if (mcpBridge) {
|
|
273
|
+
const mcpResult = parseXmlMcpToolCall(xmlString, mcpBridge.getToolNames());
|
|
274
|
+
if (mcpResult) {
|
|
275
|
+
return { ...mcpResult, type: 'mcp' };
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Parse native XML tool (existing format)
|
|
284
|
+
* @param {string} xmlString - XML string
|
|
285
|
+
* @param {string} toolName - Tool name to look for
|
|
286
|
+
* @returns {Object|null} Parsed tool call
|
|
287
|
+
*/
|
|
288
|
+
function parseNativeXmlTool(xmlString, toolName) {
|
|
289
|
+
const openTag = `<${toolName}>`;
|
|
290
|
+
const closeTag = `</${toolName}>`;
|
|
291
|
+
|
|
292
|
+
const openIndex = xmlString.indexOf(openTag);
|
|
293
|
+
if (openIndex === -1) return null;
|
|
294
|
+
|
|
295
|
+
const closeIndex = xmlString.indexOf(closeTag, openIndex);
|
|
296
|
+
if (closeIndex === -1) return null;
|
|
297
|
+
|
|
298
|
+
const contentStart = openIndex + openTag.length;
|
|
299
|
+
const content = xmlString.substring(contentStart, closeIndex).trim();
|
|
300
|
+
|
|
301
|
+
// Parse individual XML parameters (native format)
|
|
302
|
+
const params = {};
|
|
303
|
+
const paramPattern = /<(\w+)>([\s\S]*?)<\/\1>/g;
|
|
304
|
+
let match;
|
|
305
|
+
|
|
306
|
+
while ((match = paramPattern.exec(content)) !== null) {
|
|
307
|
+
const [, paramName, paramValue] = match;
|
|
308
|
+
// Skip if this is the params tag itself (MCP format)
|
|
309
|
+
if (paramName !== 'params') {
|
|
310
|
+
params[paramName] = paramValue.trim();
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Only return if we found actual parameters (not MCP format)
|
|
315
|
+
if (Object.keys(params).length > 0) {
|
|
316
|
+
return { toolName, params };
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Create a combined system message with both native and MCP tools
|
|
324
|
+
* @param {string} baseSystemMessage - Base system message
|
|
325
|
+
* @param {string} nativeToolDefinitions - Native tool definitions in XML format
|
|
326
|
+
* @param {MCPXmlBridge} mcpBridge - MCP bridge with loaded tools
|
|
327
|
+
* @returns {string} Combined system message
|
|
328
|
+
*/
|
|
329
|
+
export function createHybridSystemMessage(baseSystemMessage, nativeToolDefinitions, mcpBridge) {
|
|
330
|
+
let message = baseSystemMessage;
|
|
331
|
+
|
|
332
|
+
// Add native tools section
|
|
333
|
+
if (nativeToolDefinitions) {
|
|
334
|
+
message += '\n\n=== NATIVE TOOLS ===\n';
|
|
335
|
+
message += 'These tools use standard XML parameter format:\n\n';
|
|
336
|
+
message += nativeToolDefinitions;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Add MCP tools section if available
|
|
340
|
+
if (mcpBridge && mcpBridge.getToolNames().length > 0) {
|
|
341
|
+
message += '\n\n=== MCP TOOLS ===\n';
|
|
342
|
+
message += 'These tools use JSON parameters within the params tag:\n\n';
|
|
343
|
+
message += mcpBridge.getXmlToolDefinitions();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Add usage instructions
|
|
347
|
+
message += '\n\n=== TOOL USAGE INSTRUCTIONS ===\n';
|
|
348
|
+
message += `
|
|
349
|
+
For NATIVE tools, use standard XML format:
|
|
350
|
+
<search>
|
|
351
|
+
<query>authentication</query>
|
|
352
|
+
<path>./src</path>
|
|
353
|
+
</search>
|
|
354
|
+
|
|
355
|
+
For MCP tools, use JSON within params tag:
|
|
356
|
+
<mcp_tool_name>
|
|
357
|
+
<params>
|
|
358
|
+
{
|
|
359
|
+
"param1": "value1",
|
|
360
|
+
"param2": 123
|
|
361
|
+
}
|
|
362
|
+
</params>
|
|
363
|
+
</mcp_tool_name>
|
|
364
|
+
|
|
365
|
+
IMPORTANT: Always check the tool definition to determine whether it's a native tool (XML params) or MCP tool (JSON params).
|
|
366
|
+
`;
|
|
367
|
+
|
|
368
|
+
return message;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export default MCPXmlBridge;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock AI provider for testing purposes
|
|
3
|
+
* This provider simulates AI responses without making actual API calls
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export function createMockProvider() {
|
|
7
|
+
return {
|
|
8
|
+
languageModel: (modelName) => ({
|
|
9
|
+
modelId: `mock-${modelName}`,
|
|
10
|
+
provider: 'mock',
|
|
11
|
+
|
|
12
|
+
// Mock the doGenerate method used by Vercel AI SDK
|
|
13
|
+
doGenerate: async ({ messages, tools }) => {
|
|
14
|
+
// Simulate processing time
|
|
15
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
16
|
+
|
|
17
|
+
// Return a mock response
|
|
18
|
+
return {
|
|
19
|
+
text: 'This is a mock response for testing',
|
|
20
|
+
toolCalls: [],
|
|
21
|
+
usage: {
|
|
22
|
+
promptTokens: 10,
|
|
23
|
+
completionTokens: 5,
|
|
24
|
+
totalTokens: 15
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
// Mock the doStream method for streaming responses
|
|
30
|
+
doStream: async function* ({ messages, tools }) {
|
|
31
|
+
// Simulate streaming response
|
|
32
|
+
yield {
|
|
33
|
+
type: 'text-delta',
|
|
34
|
+
textDelta: 'Mock streaming response'
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
yield {
|
|
38
|
+
type: 'finish',
|
|
39
|
+
usage: {
|
|
40
|
+
promptTokens: 10,
|
|
41
|
+
completionTokens: 5,
|
|
42
|
+
totalTokens: 15
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function createMockModel(modelName = 'mock-model') {
|
|
51
|
+
const provider = createMockProvider();
|
|
52
|
+
return provider.languageModel(modelName);
|
|
53
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
// Simplified tool wrapper for probe agent (based on examples/chat/probeTool.js)
|
|
2
|
+
import { listFilesByLevel } from '../index.js';
|
|
3
|
+
import { exec } from 'child_process';
|
|
4
|
+
import { promisify } from 'util';
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
import { EventEmitter } from 'events';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
import { promises as fsPromises } from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { glob } from 'glob';
|
|
11
|
+
|
|
12
|
+
// Create an event emitter for tool calls (simplified for single-shot operations)
|
|
13
|
+
export const toolCallEmitter = new EventEmitter();
|
|
14
|
+
|
|
15
|
+
// Map to track active tool executions by session ID
|
|
16
|
+
const activeToolExecutions = new Map();
|
|
17
|
+
|
|
18
|
+
// Function to check if a session has been cancelled
|
|
19
|
+
export function isSessionCancelled(sessionId) {
|
|
20
|
+
return activeToolExecutions.get(sessionId)?.cancelled || false;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Function to cancel all tool executions for a session
|
|
24
|
+
export function cancelToolExecutions(sessionId) {
|
|
25
|
+
if (process.env.DEBUG === '1') {
|
|
26
|
+
console.log(`Cancelling tool executions for session: ${sessionId}`);
|
|
27
|
+
}
|
|
28
|
+
const sessionData = activeToolExecutions.get(sessionId);
|
|
29
|
+
if (sessionData) {
|
|
30
|
+
sessionData.cancelled = true;
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Function to register a new tool execution
|
|
37
|
+
function registerToolExecution(sessionId) {
|
|
38
|
+
if (!sessionId) return;
|
|
39
|
+
|
|
40
|
+
if (!activeToolExecutions.has(sessionId)) {
|
|
41
|
+
activeToolExecutions.set(sessionId, { cancelled: false });
|
|
42
|
+
} else {
|
|
43
|
+
// Reset cancelled flag if session already exists for a new execution
|
|
44
|
+
activeToolExecutions.get(sessionId).cancelled = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Function to clear tool execution data for a session
|
|
49
|
+
export function clearToolExecutionData(sessionId) {
|
|
50
|
+
if (!sessionId) return;
|
|
51
|
+
|
|
52
|
+
if (activeToolExecutions.has(sessionId)) {
|
|
53
|
+
activeToolExecutions.delete(sessionId);
|
|
54
|
+
if (process.env.DEBUG === '1') {
|
|
55
|
+
console.log(`Cleared tool execution data for session: ${sessionId}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Wrap the tools to emit events and handle cancellation
|
|
61
|
+
const wrapToolWithEmitter = (tool, toolName, baseExecute) => {
|
|
62
|
+
return {
|
|
63
|
+
...tool, // Spread schema, description etc.
|
|
64
|
+
execute: async (params) => { // The execute function now receives parsed params
|
|
65
|
+
const debug = process.env.DEBUG === '1';
|
|
66
|
+
// Get the session ID from params (passed down from ProbeAgent)
|
|
67
|
+
const toolSessionId = params.sessionId || randomUUID();
|
|
68
|
+
|
|
69
|
+
if (debug) {
|
|
70
|
+
console.log(`[DEBUG] probeTool: Executing ${toolName} for session ${toolSessionId}`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
registerToolExecution(toolSessionId);
|
|
74
|
+
|
|
75
|
+
let executionError = null;
|
|
76
|
+
let result = null;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// Emit the tool call start event
|
|
80
|
+
const toolCallStartData = {
|
|
81
|
+
timestamp: new Date().toISOString(),
|
|
82
|
+
name: toolName,
|
|
83
|
+
args: params,
|
|
84
|
+
status: 'started'
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
if (debug) {
|
|
88
|
+
console.log(`[DEBUG] probeTool: Emitting toolCallStart:${toolSessionId}`);
|
|
89
|
+
}
|
|
90
|
+
toolCallEmitter.emit(`toolCall:${toolSessionId}`, toolCallStartData);
|
|
91
|
+
|
|
92
|
+
// Check for cancellation before execution
|
|
93
|
+
if (isSessionCancelled(toolSessionId)) {
|
|
94
|
+
if (debug) {
|
|
95
|
+
console.log(`Tool execution cancelled before start for ${toolSessionId}`);
|
|
96
|
+
}
|
|
97
|
+
throw new Error(`Tool execution cancelled for session ${toolSessionId}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Execute the base function
|
|
101
|
+
result = await baseExecute(params);
|
|
102
|
+
|
|
103
|
+
// Check for cancellation after execution
|
|
104
|
+
if (isSessionCancelled(toolSessionId)) {
|
|
105
|
+
if (debug) {
|
|
106
|
+
console.log(`Tool execution cancelled after completion for ${toolSessionId}`);
|
|
107
|
+
}
|
|
108
|
+
throw new Error(`Tool execution cancelled for session ${toolSessionId}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
} catch (error) {
|
|
112
|
+
executionError = error;
|
|
113
|
+
if (debug) {
|
|
114
|
+
console.error(`[DEBUG] probeTool: Error in ${toolName}:`, error);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Handle execution results and emit appropriate events
|
|
119
|
+
if (executionError) {
|
|
120
|
+
const toolCallErrorData = {
|
|
121
|
+
timestamp: new Date().toISOString(),
|
|
122
|
+
name: toolName,
|
|
123
|
+
args: params,
|
|
124
|
+
error: executionError.message || 'Unknown error',
|
|
125
|
+
status: 'error'
|
|
126
|
+
};
|
|
127
|
+
if (debug) {
|
|
128
|
+
console.log(`[DEBUG] probeTool: Emitting toolCall:${toolSessionId} (error)`);
|
|
129
|
+
}
|
|
130
|
+
toolCallEmitter.emit(`toolCall:${toolSessionId}`, toolCallErrorData);
|
|
131
|
+
|
|
132
|
+
throw executionError;
|
|
133
|
+
} else {
|
|
134
|
+
// If loop exited due to cancellation within the loop
|
|
135
|
+
if (isSessionCancelled(toolSessionId)) {
|
|
136
|
+
if (process.env.DEBUG === '1') {
|
|
137
|
+
console.log(`Tool execution finished but session was cancelled for ${toolSessionId}`);
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Tool execution cancelled for session ${toolSessionId}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Emit the tool call completion event
|
|
143
|
+
const toolCallData = {
|
|
144
|
+
timestamp: new Date().toISOString(),
|
|
145
|
+
name: toolName,
|
|
146
|
+
args: params,
|
|
147
|
+
// Safely preview result
|
|
148
|
+
resultPreview: typeof result === 'string'
|
|
149
|
+
? (result.length > 200 ? result.substring(0, 200) + '...' : result)
|
|
150
|
+
: (result ? JSON.stringify(result).substring(0, 200) + '...' : 'No Result'),
|
|
151
|
+
status: 'completed'
|
|
152
|
+
};
|
|
153
|
+
if (debug) {
|
|
154
|
+
console.log(`[DEBUG] probeTool: Emitting toolCall:${toolSessionId} (completed)`);
|
|
155
|
+
}
|
|
156
|
+
toolCallEmitter.emit(`toolCall:${toolSessionId}`, toolCallData);
|
|
157
|
+
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Create wrapped tool instances - these will be created by the ProbeAgent
|
|
165
|
+
export function createWrappedTools(baseTools) {
|
|
166
|
+
const wrappedTools = {};
|
|
167
|
+
|
|
168
|
+
// Wrap search tool
|
|
169
|
+
if (baseTools.searchTool) {
|
|
170
|
+
wrappedTools.searchToolInstance = wrapToolWithEmitter(
|
|
171
|
+
baseTools.searchTool,
|
|
172
|
+
'search',
|
|
173
|
+
baseTools.searchTool.execute
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Wrap query tool
|
|
178
|
+
if (baseTools.queryTool) {
|
|
179
|
+
wrappedTools.queryToolInstance = wrapToolWithEmitter(
|
|
180
|
+
baseTools.queryTool,
|
|
181
|
+
'query',
|
|
182
|
+
baseTools.queryTool.execute
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Wrap extract tool
|
|
187
|
+
if (baseTools.extractTool) {
|
|
188
|
+
wrappedTools.extractToolInstance = wrapToolWithEmitter(
|
|
189
|
+
baseTools.extractTool,
|
|
190
|
+
'extract',
|
|
191
|
+
baseTools.extractTool.execute
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Wrap delegate tool
|
|
196
|
+
if (baseTools.delegateTool) {
|
|
197
|
+
wrappedTools.delegateToolInstance = wrapToolWithEmitter(
|
|
198
|
+
baseTools.delegateTool,
|
|
199
|
+
'delegate',
|
|
200
|
+
baseTools.delegateTool.execute
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return wrappedTools;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Simple file listing tool
|
|
208
|
+
export const listFilesTool = {
|
|
209
|
+
execute: async (params) => {
|
|
210
|
+
const { directory = '.' } = params;
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const files = await listFilesByLevel({
|
|
214
|
+
directory,
|
|
215
|
+
maxFiles: 100,
|
|
216
|
+
respectGitignore: !process.env.PROBE_NO_GITIGNORE || process.env.PROBE_NO_GITIGNORE === '',
|
|
217
|
+
cwd: process.cwd()
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
return files;
|
|
221
|
+
} catch (error) {
|
|
222
|
+
throw new Error(`Failed to list files: ${error.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// Simple file search tool
|
|
228
|
+
export const searchFilesTool = {
|
|
229
|
+
execute: async (params) => {
|
|
230
|
+
const { pattern, directory = '.', recursive = true } = params;
|
|
231
|
+
|
|
232
|
+
if (!pattern) {
|
|
233
|
+
throw new Error('Pattern is required for file search');
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const options = {
|
|
238
|
+
cwd: directory,
|
|
239
|
+
ignore: ['node_modules/**', '.git/**'],
|
|
240
|
+
absolute: false
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
if (!recursive) {
|
|
244
|
+
options.deep = 1;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
const files = await glob(pattern, options);
|
|
248
|
+
return files;
|
|
249
|
+
} catch (error) {
|
|
250
|
+
throw new Error(`Failed to search files: ${error.message}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
// Wrap the additional tools
|
|
256
|
+
export const listFilesToolInstance = wrapToolWithEmitter(listFilesTool, 'listFiles', listFilesTool.execute);
|
|
257
|
+
export const searchFilesToolInstance = wrapToolWithEmitter(searchFilesTool, 'searchFiles', searchFilesTool.execute);
|