@probelabs/probe-chat 0.6.0-rc254 → 0.6.0-rc255
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/index.js +2 -72
- package/package.json +1 -2
- package/probeChat.js +1 -1
- package/probeTool.js +0 -72
- package/test/integration/toolCalling.test.js +10 -141
- package/test/mocks/mockLLMProvider.js +0 -18
- package/test/test-backends.js +3 -83
- package/test/testUtils.js +0 -45
- package/test/verify-tests.js +1 -1
- package/webServer.js +2 -28
- package/implement/README.md +0 -228
- package/implement/backends/AiderBackend.js +0 -750
- package/implement/backends/BaseBackend.js +0 -276
- package/implement/backends/ClaudeCodeBackend.js +0 -767
- package/implement/backends/MockBackend.js +0 -237
- package/implement/backends/registry.js +0 -85
- package/implement/core/BackendManager.js +0 -567
- package/implement/core/ImplementTool.js +0 -354
- package/implement/core/config.js +0 -428
- package/implement/core/timeouts.js +0 -58
- package/implement/core/utils.js +0 -496
- package/implement/types/BackendTypes.js +0 -126
package/index.js
CHANGED
|
@@ -62,12 +62,7 @@ export function main() {
|
|
|
62
62
|
.option('--json', 'Output the response as JSON in non-interactive mode')
|
|
63
63
|
.option('--max-iterations <number>', 'Maximum number of tool iterations allowed (default: 30)')
|
|
64
64
|
.option('--prompt <value>', 'Use a custom prompt (values: architect, code-review, code-review-template, support, path to a file, or arbitrary string)')
|
|
65
|
-
.option('--allow-edit', 'Enable
|
|
66
|
-
.option('--implement-tool-backend <backend>', 'Choose implementation tool backend (aider, claude-code)')
|
|
67
|
-
.option('--implement-tool-timeout <ms>', 'Implementation tool timeout in milliseconds')
|
|
68
|
-
.option('--implement-tool-config <path>', 'Path to implementation tool configuration file')
|
|
69
|
-
.option('--implement-tool-list-backends', 'List available implementation tool backends')
|
|
70
|
-
.option('--implement-tool-backend-info <backend>', 'Show information about a specific implementation tool backend')
|
|
65
|
+
.option('--allow-edit', 'Enable editing files')
|
|
71
66
|
.option('--enable-bash', 'Enable bash command execution for system exploration')
|
|
72
67
|
.option('--bash-allow <patterns>', 'Additional bash command patterns to allow (comma-separated)')
|
|
73
68
|
.option('--bash-deny <patterns>', 'Additional bash command patterns to deny (comma-separated)')
|
|
@@ -165,75 +160,10 @@ export function main() {
|
|
|
165
160
|
logInfo(chalk.blue(`Setting maximum tool iterations to: ${maxIterations}`));
|
|
166
161
|
}
|
|
167
162
|
|
|
168
|
-
// Handle --implement-tool-list-backends option
|
|
169
|
-
if (options.implementToolListBackends) {
|
|
170
|
-
(async () => {
|
|
171
|
-
const { listBackendNames, getBackendMetadata } = await import('./implement/backends/registry.js');
|
|
172
|
-
const backends = listBackendNames();
|
|
173
|
-
|
|
174
|
-
console.log('\nAvailable implementation tool backends:');
|
|
175
|
-
for (const backend of backends) {
|
|
176
|
-
const metadata = getBackendMetadata(backend);
|
|
177
|
-
console.log(`\n ${chalk.bold(backend)} - ${metadata.description}`);
|
|
178
|
-
console.log(` Version: ${metadata.version}`);
|
|
179
|
-
console.log(` Languages: ${metadata.capabilities.supportsLanguages.join(', ')}`);
|
|
180
|
-
}
|
|
181
|
-
process.exit(0);
|
|
182
|
-
})();
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Handle --implement-tool-backend-info option
|
|
186
|
-
if (options.implementToolBackendInfo) {
|
|
187
|
-
(async () => {
|
|
188
|
-
const { getBackendMetadata } = await import('./implement/backends/registry.js');
|
|
189
|
-
const metadata = getBackendMetadata(options.implementToolBackendInfo);
|
|
190
|
-
|
|
191
|
-
if (!metadata) {
|
|
192
|
-
console.error(`Backend '${options.implementToolBackendInfo}' not found`);
|
|
193
|
-
process.exit(1);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
console.log(`\n${chalk.bold('Backend Information: ' + options.implementToolBackendInfo)}`);
|
|
197
|
-
console.log(`\nDescription: ${metadata.description}`);
|
|
198
|
-
console.log(`Version: ${metadata.version}`);
|
|
199
|
-
console.log(`\nCapabilities:`);
|
|
200
|
-
console.log(` Languages: ${metadata.capabilities.supportsLanguages.join(', ')}`);
|
|
201
|
-
console.log(` Streaming: ${metadata.capabilities.supportsStreaming ? '✓' : '✗'}`);
|
|
202
|
-
console.log(` Direct File Edit: ${metadata.capabilities.supportsDirectFileEdit ? '✓' : '✗'}`);
|
|
203
|
-
console.log(` Test Generation: ${metadata.capabilities.supportsTestGeneration ? '✓' : '✗'}`);
|
|
204
|
-
console.log(` Plan Generation: ${metadata.capabilities.supportsPlanGeneration ? '✓' : '✗'}`);
|
|
205
|
-
console.log(` Max Sessions: ${metadata.capabilities.maxConcurrentSessions}`);
|
|
206
|
-
console.log(`\nRequired Dependencies:`);
|
|
207
|
-
for (const dep of metadata.dependencies) {
|
|
208
|
-
console.log(` - ${dep.name} (${dep.type}): ${dep.description}`);
|
|
209
|
-
if (dep.installCommand) {
|
|
210
|
-
console.log(` Install: ${dep.installCommand}`);
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
process.exit(0);
|
|
214
|
-
})();
|
|
215
|
-
}
|
|
216
|
-
|
|
217
163
|
// Set ALLOW_EDIT from command line if provided
|
|
218
164
|
if (options.allowEdit) {
|
|
219
165
|
process.env.ALLOW_EDIT = '1';
|
|
220
|
-
logInfo(chalk.blue(`Enabling
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
// Set implementation tool backend options
|
|
224
|
-
if (options.implementToolBackend) {
|
|
225
|
-
process.env.IMPLEMENT_TOOL_BACKEND = options.implementToolBackend;
|
|
226
|
-
logInfo(chalk.blue(`Using implementation tool backend: ${options.implementToolBackend}`));
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
if (options.implementToolTimeout) {
|
|
230
|
-
process.env.IMPLEMENT_TOOL_TIMEOUT = options.implementToolTimeout;
|
|
231
|
-
logInfo(chalk.blue(`Implementation tool timeout: ${options.implementToolTimeout}ms`));
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
if (options.implementToolConfig) {
|
|
235
|
-
process.env.IMPLEMENT_TOOL_CONFIG_PATH = options.implementToolConfig;
|
|
236
|
-
logInfo(chalk.blue(`Using implementation tool config: ${options.implementToolConfig}`));
|
|
166
|
+
logInfo(chalk.blue(`Enabling edit mode with --allow-edit flag`));
|
|
237
167
|
}
|
|
238
168
|
|
|
239
169
|
// Set telemetry options from command line if provided
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@probelabs/probe-chat",
|
|
3
|
-
"version": "0.6.0-
|
|
3
|
+
"version": "0.6.0-rc255",
|
|
4
4
|
"description": "CLI and web interface for Probe code search (formerly @probelabs/probe-web and @probelabs/probe-chat)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -78,7 +78,6 @@
|
|
|
78
78
|
"files": [
|
|
79
79
|
"bin/",
|
|
80
80
|
"storage/",
|
|
81
|
-
"implement/",
|
|
82
81
|
"test/",
|
|
83
82
|
"index.js",
|
|
84
83
|
"probeChat.js",
|
package/probeChat.js
CHANGED
|
@@ -253,7 +253,7 @@ export class ProbeChat {
|
|
|
253
253
|
* @param {boolean} [options.isNonInteractive=false] - Suppress internal logs if true
|
|
254
254
|
* @param {string} [options.customPrompt] - Custom prompt to replace the default system message
|
|
255
255
|
* @param {string} [options.promptType] - Predefined prompt type (architect, code-review, support)
|
|
256
|
-
* @param {boolean} [options.allowEdit=false] - Allow the use of the '
|
|
256
|
+
* @param {boolean} [options.allowEdit=false] - Allow the use of the 'edit' and 'create' tools
|
|
257
257
|
* @param {string} [options.architectureFileName] - Architecture context filename to embed from repo root (defaults to AGENTS.md with CLAUDE.md fallback; ARCHITECTURE.md is always included when present)
|
|
258
258
|
* @param {string} [options.provider] - Force specific AI provider
|
|
259
259
|
* @param {string} [options.model] - Override model name
|
package/probeTool.js
CHANGED
|
@@ -11,9 +11,6 @@ import { spawn } from 'child_process';
|
|
|
11
11
|
import { randomUUID } from 'crypto';
|
|
12
12
|
import { EventEmitter } from 'events';
|
|
13
13
|
|
|
14
|
-
// Import the new pluggable implementation tool
|
|
15
|
-
import { createImplementTool } from './implement/core/ImplementTool.js';
|
|
16
|
-
|
|
17
14
|
// Create an event emitter for tool calls
|
|
18
15
|
export const toolCallEmitter = new EventEmitter();
|
|
19
16
|
|
|
@@ -257,73 +254,6 @@ const wrapToolWithEmitter = (tool, toolName, baseExecute) => {
|
|
|
257
254
|
};
|
|
258
255
|
};
|
|
259
256
|
|
|
260
|
-
// Create the implement tool using the new pluggable system
|
|
261
|
-
const implementToolConfig = {
|
|
262
|
-
enabled: process.env.ALLOW_EDIT === '1' || process.argv.includes('--allow-edit'),
|
|
263
|
-
backendConfig: {
|
|
264
|
-
// Configuration can be extended here
|
|
265
|
-
}
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
const pluggableImplementTool = createImplementTool(implementToolConfig);
|
|
269
|
-
|
|
270
|
-
// Create a compatibility wrapper for the old interface
|
|
271
|
-
const baseImplementTool = {
|
|
272
|
-
name: "implement",
|
|
273
|
-
description: pluggableImplementTool.description,
|
|
274
|
-
inputSchema: pluggableImplementTool.inputSchema,
|
|
275
|
-
execute: async ({ task, autoCommits = false, prompt, sessionId }) => {
|
|
276
|
-
const debug = process.env.DEBUG_CHAT === '1';
|
|
277
|
-
|
|
278
|
-
if (debug) {
|
|
279
|
-
console.log(`[DEBUG] Executing implementation with task: ${task}`);
|
|
280
|
-
console.log(`[DEBUG] Auto-commits: ${autoCommits}`);
|
|
281
|
-
console.log(`[DEBUG] Session ID: ${sessionId}`);
|
|
282
|
-
if (prompt) console.log(`[DEBUG] Custom prompt: ${prompt}`);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// Check if the tool is enabled
|
|
286
|
-
if (!implementToolConfig.enabled) {
|
|
287
|
-
return {
|
|
288
|
-
success: false,
|
|
289
|
-
output: null,
|
|
290
|
-
error: 'Implementation tool is not enabled. Use --allow-edit flag to enable.',
|
|
291
|
-
command: null,
|
|
292
|
-
timestamp: new Date().toISOString(),
|
|
293
|
-
prompt: prompt || task
|
|
294
|
-
};
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
try {
|
|
298
|
-
// Use the new pluggable implementation tool
|
|
299
|
-
const result = await pluggableImplementTool.execute({
|
|
300
|
-
task: prompt || task, // Use prompt if provided, otherwise use task
|
|
301
|
-
autoCommit: autoCommits,
|
|
302
|
-
sessionId: sessionId,
|
|
303
|
-
// Pass through any additional options that might be useful
|
|
304
|
-
context: {
|
|
305
|
-
workingDirectory: process.cwd()
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
|
|
309
|
-
// The result is already in the expected format
|
|
310
|
-
return result;
|
|
311
|
-
|
|
312
|
-
} catch (error) {
|
|
313
|
-
// Handle any unexpected errors
|
|
314
|
-
console.error(`Error in implement tool:`, error);
|
|
315
|
-
return {
|
|
316
|
-
success: false,
|
|
317
|
-
output: null,
|
|
318
|
-
error: error.message || 'Unknown error in implementation tool',
|
|
319
|
-
command: null,
|
|
320
|
-
timestamp: new Date().toISOString(),
|
|
321
|
-
prompt: prompt || task
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
|
-
|
|
327
257
|
// Wrapper for listFiles tool with ALLOWED_FOLDERS security
|
|
328
258
|
const baseListFilesTool = {
|
|
329
259
|
...packageListFilesToolInstance,
|
|
@@ -472,7 +402,6 @@ const baseSearchFilesTool = {
|
|
|
472
402
|
export const searchToolInstance = wrapToolWithEmitter(baseSearchTool, 'search', baseSearchTool.execute);
|
|
473
403
|
export const queryToolInstance = wrapToolWithEmitter(baseQueryTool, 'query', baseQueryTool.execute);
|
|
474
404
|
export const extractToolInstance = wrapToolWithEmitter(baseExtractTool, 'extract', baseExtractTool.execute);
|
|
475
|
-
export const implementToolInstance = wrapToolWithEmitter(baseImplementTool, 'implement', baseImplementTool.execute);
|
|
476
405
|
export const listFilesToolInstance = wrapToolWithEmitter(baseListFilesTool, 'listFiles', baseListFilesTool.execute);
|
|
477
406
|
export const searchFilesToolInstance = wrapToolWithEmitter(baseSearchFilesTool, 'searchFiles', baseSearchFilesTool.execute);
|
|
478
407
|
|
|
@@ -483,7 +412,6 @@ if (process.env.DEBUG_CHAT === '1') {
|
|
|
483
412
|
console.log('[DEBUG] - search: Search for code patterns');
|
|
484
413
|
console.log('[DEBUG] - query: Semantic code search');
|
|
485
414
|
console.log('[DEBUG] - extract: Extract code snippets');
|
|
486
|
-
console.log('[DEBUG] - implement: Generate code implementations');
|
|
487
415
|
console.log('[DEBUG] - listFiles: List directory contents');
|
|
488
416
|
console.log('[DEBUG] - searchFiles: Search files by pattern');
|
|
489
417
|
console.log('[DEBUG] ========================================\n');
|
|
@@ -143,123 +143,6 @@ describe('Tool Calling Integration Tests', () => {
|
|
|
143
143
|
});
|
|
144
144
|
});
|
|
145
145
|
|
|
146
|
-
describe('Implement Tool', () => {
|
|
147
|
-
it('should handle implement tool calls', async () => {
|
|
148
|
-
const { probeChat, mockBackend } = await createTestProbeChat({
|
|
149
|
-
responses: [
|
|
150
|
-
mockResponses.implementToolCall,
|
|
151
|
-
{ text: 'The implementation is complete!' }
|
|
152
|
-
],
|
|
153
|
-
useMockBackend: true,
|
|
154
|
-
mockBackendResponses: [{
|
|
155
|
-
filesModified: ['src/math.js'],
|
|
156
|
-
summary: 'Added fibonacci function'
|
|
157
|
-
}]
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
const results = await runChatInteraction(probeChat,
|
|
161
|
-
[{ role: 'user', content: 'Add a fibonacci function to math.js' }]
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
assert.strictEqual(results.toolCalls.length, 1);
|
|
165
|
-
assert.strictEqual(results.toolCalls[0].toolName, 'implement');
|
|
166
|
-
assert.strictEqual(mockBackend.capturedRequests.length, 1);
|
|
167
|
-
|
|
168
|
-
const request = mockBackend.getLastRequest();
|
|
169
|
-
assert.strictEqual(request.request.request, 'Add a new function to calculate fibonacci numbers');
|
|
170
|
-
assert.deepStrictEqual(request.request.files, ['src/math.js']);
|
|
171
|
-
assert.strictEqual(request.request.backend, 'mock');
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('should handle implement tool with streaming', async () => {
|
|
175
|
-
const { probeChat, mockBackend } = await createTestProbeChat({
|
|
176
|
-
responses: [
|
|
177
|
-
mockResponses.implementToolCall,
|
|
178
|
-
{ text: 'Implementation completed with streaming!' }
|
|
179
|
-
],
|
|
180
|
-
useMockBackend: true,
|
|
181
|
-
mockBackendResponses: [{
|
|
182
|
-
stream: [
|
|
183
|
-
{ type: 'start', message: 'Starting implementation' },
|
|
184
|
-
{ type: 'progress', message: 'Generating code' },
|
|
185
|
-
{ type: 'file_update', file: 'src/math.js', action: 'modified' },
|
|
186
|
-
{ type: 'complete', message: 'Done' }
|
|
187
|
-
],
|
|
188
|
-
filesModified: ['src/math.js']
|
|
189
|
-
}]
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
mockBackend.setResponseDelay(50); // Fast streaming for tests
|
|
193
|
-
|
|
194
|
-
let streamEvents = [];
|
|
195
|
-
const originalImplementExecute = probeChat.tools.implement.execute;
|
|
196
|
-
probeChat.tools.implement.execute = async function(args) {
|
|
197
|
-
return originalImplementExecute.call(this, args, {
|
|
198
|
-
onProgress: (event) => {
|
|
199
|
-
streamEvents.push(event);
|
|
200
|
-
}
|
|
201
|
-
});
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
await runChatInteraction(probeChat,
|
|
205
|
-
[{ role: 'user', content: 'Implement fibonacci with streaming' }]
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
assert.ok(streamEvents.length >= 4, 'Should receive multiple stream events');
|
|
209
|
-
assert.strictEqual(streamEvents[0].type, 'start');
|
|
210
|
-
assert.strictEqual(streamEvents[streamEvents.length - 1].type, 'complete');
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
it('should handle backend selection', async () => {
|
|
214
|
-
const { probeChat, mockBackend } = await createTestProbeChat({
|
|
215
|
-
responses: [{
|
|
216
|
-
text: 'I will use the mock backend.',
|
|
217
|
-
toolCalls: [{
|
|
218
|
-
toolName: 'implement',
|
|
219
|
-
args: {
|
|
220
|
-
request: 'Test backend selection',
|
|
221
|
-
backend: 'mock'
|
|
222
|
-
}
|
|
223
|
-
}]
|
|
224
|
-
}, { text: 'Done with mock backend.' }],
|
|
225
|
-
useMockBackend: true
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
await runChatInteraction(probeChat,
|
|
229
|
-
[{ role: 'user', content: 'Implement something using mock backend' }]
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const request = mockBackend.getLastRequest();
|
|
233
|
-
assert.ok(request, 'Should capture the request');
|
|
234
|
-
assert.strictEqual(request.request.backend, 'mock');
|
|
235
|
-
});
|
|
236
|
-
|
|
237
|
-
it('should handle backend errors', async () => {
|
|
238
|
-
const { probeChat, mockBackend } = await createTestProbeChat({
|
|
239
|
-
responses: [
|
|
240
|
-
mockResponses.implementToolCall,
|
|
241
|
-
{ text: 'The implementation failed, but I handled it gracefully.' }
|
|
242
|
-
],
|
|
243
|
-
useMockBackend: true
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
mockBackend.setErrorMode(true);
|
|
247
|
-
|
|
248
|
-
let toolError;
|
|
249
|
-
probeChat.tools.implement.handleError = (error) => {
|
|
250
|
-
toolError = error;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
const results = await runChatInteraction(probeChat,
|
|
254
|
-
[{ role: 'user', content: 'Try to implement with error' }]
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
// The tool should handle the error gracefully
|
|
258
|
-
assert.strictEqual(results.errors.length, 0, 'Chat should not error');
|
|
259
|
-
assert.ok(toolError, 'Tool should capture the error');
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
|
|
263
146
|
describe('Query Tool', () => {
|
|
264
147
|
it('should handle semantic query tool calls', async () => {
|
|
265
148
|
const { probeChat } = await createTestProbeChat({
|
|
@@ -417,8 +300,8 @@ describe('Tool Calling Integration Tests', () => {
|
|
|
417
300
|
});
|
|
418
301
|
|
|
419
302
|
describe('Complex Tool Sequences', () => {
|
|
420
|
-
it('should handle search → extract
|
|
421
|
-
const { probeChat
|
|
303
|
+
it('should handle search → extract workflow', async () => {
|
|
304
|
+
const { probeChat } = await createTestProbeChat({
|
|
422
305
|
responses: [
|
|
423
306
|
{
|
|
424
307
|
text: 'Let me search for existing implementations.',
|
|
@@ -434,38 +317,24 @@ describe('Tool Calling Integration Tests', () => {
|
|
|
434
317
|
args: { location: 'src/math.js:fibonacci' }
|
|
435
318
|
}]
|
|
436
319
|
},
|
|
437
|
-
{
|
|
438
|
-
|
|
439
|
-
toolCalls: [{
|
|
440
|
-
toolName: 'implement',
|
|
441
|
-
args: {
|
|
442
|
-
request: 'Optimize fibonacci with memoization',
|
|
443
|
-
files: ['src/math.js'],
|
|
444
|
-
backend: 'mock'
|
|
445
|
-
}
|
|
446
|
-
}]
|
|
447
|
-
},
|
|
448
|
-
{ text: 'Successfully optimized the fibonacci function!' }
|
|
449
|
-
],
|
|
450
|
-
useMockBackend: true
|
|
320
|
+
{ text: 'Here is the fibonacci function!' }
|
|
321
|
+
]
|
|
451
322
|
});
|
|
452
|
-
|
|
323
|
+
|
|
453
324
|
// Mock tool implementations
|
|
454
325
|
probeChat.tools.probe_search.execute = async () => createMockProbeResults();
|
|
455
326
|
probeChat.tools.probe_extract.execute = async () => ({
|
|
456
327
|
content: testData.sampleCode.javascript,
|
|
457
328
|
language: 'javascript'
|
|
458
329
|
});
|
|
459
|
-
|
|
460
|
-
const results = await runChatInteraction(probeChat,
|
|
461
|
-
[{ role: 'user', content: '
|
|
330
|
+
|
|
331
|
+
const results = await runChatInteraction(probeChat,
|
|
332
|
+
[{ role: 'user', content: 'Find and show the fibonacci function' }]
|
|
462
333
|
);
|
|
463
|
-
|
|
464
|
-
assert.strictEqual(results.toolCalls.length,
|
|
334
|
+
|
|
335
|
+
assert.strictEqual(results.toolCalls.length, 2);
|
|
465
336
|
assert.strictEqual(results.toolCalls[0].toolName, 'probe_search');
|
|
466
337
|
assert.strictEqual(results.toolCalls[1].toolName, 'probe_extract');
|
|
467
|
-
assert.strictEqual(results.toolCalls[2].toolName, 'implement');
|
|
468
|
-
assert.strictEqual(mockBackend.capturedRequests.length, 1);
|
|
469
338
|
});
|
|
470
339
|
});
|
|
471
340
|
});
|
|
@@ -209,19 +209,6 @@ export const mockResponses = {
|
|
|
209
209
|
]
|
|
210
210
|
},
|
|
211
211
|
|
|
212
|
-
// Implement tool call
|
|
213
|
-
implementToolCall: {
|
|
214
|
-
text: "I'll implement that feature for you.",
|
|
215
|
-
toolCalls: [{
|
|
216
|
-
toolName: 'implement',
|
|
217
|
-
args: {
|
|
218
|
-
request: 'Add a new function to calculate fibonacci numbers',
|
|
219
|
-
files: ['src/math.js'],
|
|
220
|
-
backend: 'mock'
|
|
221
|
-
}
|
|
222
|
-
}]
|
|
223
|
-
},
|
|
224
|
-
|
|
225
212
|
// Error response
|
|
226
213
|
errorResponse: {
|
|
227
214
|
text: "I encountered an error processing your request.",
|
|
@@ -249,17 +236,12 @@ export function createMockProvider(scenario = 'simple', options = {}) {
|
|
|
249
236
|
responses.push(mockResponses.withToolCall);
|
|
250
237
|
responses.push(mockResponses.simpleText);
|
|
251
238
|
break;
|
|
252
|
-
case 'implement':
|
|
253
|
-
responses.push(mockResponses.implementToolCall);
|
|
254
|
-
responses.push({ text: "The implementation is complete!" });
|
|
255
|
-
break;
|
|
256
239
|
case 'error':
|
|
257
240
|
return new MockLLMProvider({ ...options, throwError: 'Simulated API error' });
|
|
258
241
|
case 'mixed':
|
|
259
242
|
responses.push(mockResponses.simpleText);
|
|
260
243
|
responses.push(mockResponses.withToolCall);
|
|
261
244
|
responses.push(mockResponses.multipleToolCalls);
|
|
262
|
-
responses.push(mockResponses.implementToolCall);
|
|
263
245
|
break;
|
|
264
246
|
default:
|
|
265
247
|
responses.push(mockResponses.simpleText);
|
package/test/test-backends.js
CHANGED
|
@@ -4,87 +4,7 @@
|
|
|
4
4
|
* Simple test script for the pluggable backend system
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
// Backend test file - implement tool has been removed.
|
|
8
|
+
// This file is no longer needed.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
console.log('🧪 Testing Probe Chat Pluggable Backend System\n');
|
|
12
|
-
|
|
13
|
-
// List available backends
|
|
14
|
-
console.log('📋 Available Backends:');
|
|
15
|
-
const backends = listBackendNames();
|
|
16
|
-
for (const backend of backends) {
|
|
17
|
-
const metadata = getBackendMetadata(backend);
|
|
18
|
-
console.log(`\n ${backend}:`);
|
|
19
|
-
console.log(` Version: ${metadata.version}`);
|
|
20
|
-
console.log(` Description: ${metadata.description}`);
|
|
21
|
-
console.log(` Languages: ${metadata.capabilities.supportsLanguages.join(', ')}`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
console.log('\n' + '='.repeat(50) + '\n');
|
|
25
|
-
|
|
26
|
-
// Test backend initialization
|
|
27
|
-
console.log('🔧 Testing Backend Initialization:\n');
|
|
28
|
-
|
|
29
|
-
const tool = createImplementTool({
|
|
30
|
-
enabled: true,
|
|
31
|
-
backendConfig: {
|
|
32
|
-
defaultBackend: 'aider',
|
|
33
|
-
fallbackBackends: ['claude-code']
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
const info = await tool.getInfo();
|
|
39
|
-
console.log('✅ Backend system initialized successfully');
|
|
40
|
-
console.log(` Default backend: ${info.defaultBackend}`);
|
|
41
|
-
console.log(` Fallback backends: ${info.fallbackBackends.join(', ')}`);
|
|
42
|
-
console.log(` Available backends: ${info.availableBackends.join(', ')}`);
|
|
43
|
-
|
|
44
|
-
console.log('\n📊 Backend Health Status:');
|
|
45
|
-
for (const [name, health] of Object.entries(info.health)) {
|
|
46
|
-
console.log(` ${name}: ${health.status} ${health.available ? '✅' : '❌'}`);
|
|
47
|
-
}
|
|
48
|
-
} catch (error) {
|
|
49
|
-
console.error('❌ Failed to initialize backend system:', error.message);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
console.log('\n' + '='.repeat(50) + '\n');
|
|
53
|
-
|
|
54
|
-
// Test a simple implementation request (dry run)
|
|
55
|
-
console.log('🚀 Testing Implementation Request (Dry Run):\n');
|
|
56
|
-
|
|
57
|
-
const testRequest = {
|
|
58
|
-
task: 'Create a simple hello world function in JavaScript',
|
|
59
|
-
dryRun: true,
|
|
60
|
-
sessionId: 'test-' + Date.now()
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
console.log('Request:', testRequest);
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
console.log('\nExecuting request...\n');
|
|
67
|
-
const result = await tool.execute(testRequest);
|
|
68
|
-
|
|
69
|
-
if (result.success) {
|
|
70
|
-
console.log('✅ Request executed successfully');
|
|
71
|
-
console.log(` Backend used: ${result.backend}`);
|
|
72
|
-
console.log(` Execution time: ${result.metrics?.executionTime}ms`);
|
|
73
|
-
console.log('\nOutput preview:');
|
|
74
|
-
console.log(result.output?.substring(0, 200) + '...');
|
|
75
|
-
} else {
|
|
76
|
-
console.log('❌ Request failed');
|
|
77
|
-
console.log(` Error: ${result.error}`);
|
|
78
|
-
}
|
|
79
|
-
} catch (error) {
|
|
80
|
-
console.error('❌ Error executing request:', error.message);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Cleanup
|
|
84
|
-
await tool.cleanup();
|
|
85
|
-
|
|
86
|
-
console.log('\n✅ Test completed');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Run the test
|
|
90
|
-
testBackends().catch(console.error);
|
|
10
|
+
console.log('Backend tests have been removed along with the implement tool.');
|
package/test/testUtils.js
CHANGED
|
@@ -3,7 +3,6 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import { ProbeChat } from '../probeChat.js';
|
|
5
5
|
import { MockLLMProvider, createMockStreamText } from './mocks/mockLLMProvider.js';
|
|
6
|
-
import MockBackend from '../implement/backends/MockBackend.js';
|
|
7
6
|
|
|
8
7
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
8
|
const __dirname = path.dirname(__filename);
|
|
@@ -120,20 +119,6 @@ export async function createTestProbeChat(options = {}) {
|
|
|
120
119
|
};
|
|
121
120
|
}
|
|
122
121
|
},
|
|
123
|
-
implement: {
|
|
124
|
-
execute: async (args, options) => {
|
|
125
|
-
console.log('Mock implement called with:', args);
|
|
126
|
-
return {
|
|
127
|
-
sessionId: 'mock-session',
|
|
128
|
-
status: 'success',
|
|
129
|
-
filesModified: ['mock.js'],
|
|
130
|
-
summary: 'Mock implementation complete'
|
|
131
|
-
};
|
|
132
|
-
},
|
|
133
|
-
handleError: (error) => {
|
|
134
|
-
console.error('Mock implement error:', error);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
122
|
};
|
|
138
123
|
|
|
139
124
|
// Make tools accessible for test overrides
|
|
@@ -235,36 +220,6 @@ export async function createTestProbeChat(options = {}) {
|
|
|
235
220
|
return 'mock-base64-image-data';
|
|
236
221
|
};
|
|
237
222
|
|
|
238
|
-
// Register mock backend if implement tool is being tested
|
|
239
|
-
if (options.useMockBackend) {
|
|
240
|
-
const mockBackend = new MockBackend();
|
|
241
|
-
|
|
242
|
-
if (options.mockBackendResponses) {
|
|
243
|
-
mockBackend.setResponses(options.mockBackendResponses);
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// Override the implement tool's execute method to use our mock backend
|
|
247
|
-
const originalImplementExecute = probeChat.tools.implement.execute;
|
|
248
|
-
probeChat.tools.implement.execute = async function(args, options) {
|
|
249
|
-
// Force the mock backend
|
|
250
|
-
args.backend = 'mock';
|
|
251
|
-
|
|
252
|
-
// If we need to register the backend, do it here
|
|
253
|
-
if (this.backendManager) {
|
|
254
|
-
await this.backendManager.registerBackend(mockBackend);
|
|
255
|
-
} else {
|
|
256
|
-
// Direct execution with mock backend
|
|
257
|
-
return await mockBackend.implement(args, options);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return originalImplementExecute ? originalImplementExecute.call(this, args, options) :
|
|
261
|
-
await mockBackend.implement(args, options);
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
// Return both for test access
|
|
265
|
-
return { probeChat, mockProvider, mockBackend };
|
|
266
|
-
}
|
|
267
|
-
|
|
268
223
|
return { probeChat, mockProvider };
|
|
269
224
|
}
|
|
270
225
|
|
package/test/verify-tests.js
CHANGED
|
@@ -103,7 +103,7 @@ async function main() {
|
|
|
103
103
|
console.log('\n✅ All integration tests are working correctly!');
|
|
104
104
|
console.log('\nKey features verified:');
|
|
105
105
|
console.log('- Mock LLM provider with streaming support');
|
|
106
|
-
console.log('- Mock backend for
|
|
106
|
+
console.log('- Mock backend for testing');
|
|
107
107
|
console.log('- Multi-turn conversations');
|
|
108
108
|
console.log('- Tool calling and execution');
|
|
109
109
|
console.log('- Error handling and recovery');
|
package/webServer.js
CHANGED
|
@@ -13,7 +13,6 @@ import {
|
|
|
13
13
|
searchToolInstance, // Keep direct instances for API endpoints
|
|
14
14
|
queryToolInstance,
|
|
15
15
|
extractToolInstance,
|
|
16
|
-
implementToolInstance,
|
|
17
16
|
toolCallEmitter,
|
|
18
17
|
cancelToolExecutions,
|
|
19
18
|
clearToolExecutionData,
|
|
@@ -99,13 +98,13 @@ function getOrCreateChat(sessionId, apiCredentials = null) {
|
|
|
99
98
|
* Start the web server
|
|
100
99
|
* @param {string} version - The version of the application
|
|
101
100
|
* @param {Object} options - Additional options
|
|
102
|
-
* @param {boolean} options.allowEdit - Whether to allow editing files
|
|
101
|
+
* @param {boolean} options.allowEdit - Whether to allow editing files
|
|
103
102
|
*/
|
|
104
103
|
export async function startWebServer(version, options = {}) {
|
|
105
104
|
const allowEdit = options?.allowEdit || false;
|
|
106
105
|
|
|
107
106
|
if (allowEdit) {
|
|
108
|
-
console.log('Edit mode enabled
|
|
107
|
+
console.log('Edit mode enabled');
|
|
109
108
|
}
|
|
110
109
|
// Authentication configuration
|
|
111
110
|
const AUTH_ENABLED = process.env.AUTH_ENABLED === '1';
|
|
@@ -155,12 +154,6 @@ export async function startWebServer(version, options = {}) {
|
|
|
155
154
|
query: queryToolInstance,
|
|
156
155
|
extract: extractToolInstance
|
|
157
156
|
};
|
|
158
|
-
|
|
159
|
-
// Add implement tool if edit mode is enabled
|
|
160
|
-
if (allowEdit) {
|
|
161
|
-
directApiTools.implement = implementToolInstance;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
157
|
|
|
165
158
|
// Helper function to send SSE data
|
|
166
159
|
function sendSSEData(res, data, eventType = 'message') {
|
|
@@ -214,7 +207,6 @@ export async function startWebServer(version, options = {}) {
|
|
|
214
207
|
'OPTIONS /api/search': (req, res) => handleOptions(res),
|
|
215
208
|
'OPTIONS /api/query': (req, res) => handleOptions(res),
|
|
216
209
|
'OPTIONS /api/extract': (req, res) => handleOptions(res),
|
|
217
|
-
'OPTIONS /api/implement': (req, res) => handleOptions(res),
|
|
218
210
|
'OPTIONS /cancel-request': (req, res) => handleOptions(res),
|
|
219
211
|
'OPTIONS /folders': (req, res) => handleOptions(res), // Added for /folders
|
|
220
212
|
|
|
@@ -641,24 +633,6 @@ export async function startWebServer(version, options = {}) {
|
|
|
641
633
|
});
|
|
642
634
|
},
|
|
643
635
|
|
|
644
|
-
// Implement tool endpoint (only available if allowEdit is true)
|
|
645
|
-
'POST /api/implement': async (req, res) => {
|
|
646
|
-
// Check if edit mode is enabled
|
|
647
|
-
if (!directApiTools.implement) {
|
|
648
|
-
return sendError(res, 403, 'Implement tool is not enabled. Start server with --allow-edit to enable.');
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
handlePostRequest(req, res, async (body) => {
|
|
652
|
-
const { task, sessionId: reqSessionId } = body;
|
|
653
|
-
if (!task) return sendError(res, 400, 'Missing required parameter: task');
|
|
654
|
-
|
|
655
|
-
const sessionId = reqSessionId || randomUUID();
|
|
656
|
-
const toolParams = { task, sessionId };
|
|
657
|
-
|
|
658
|
-
await executeDirectTool(res, directApiTools.implement, 'implement', toolParams, sessionId);
|
|
659
|
-
});
|
|
660
|
-
},
|
|
661
|
-
|
|
662
636
|
// --- Main Chat Endpoint (Handles the Loop) ---
|
|
663
637
|
'POST /chat': (req, res) => { // This is the route used by the frontend UI
|
|
664
638
|
handlePostRequest(req, res, async (requestData) => {
|