@hanzo/dev 2.1.1 → 3.0.2
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 +278 -279
- package/bin/dev.js +413 -0
- package/package.json +32 -61
- package/postinstall.js +513 -0
- package/scripts/preinstall.js +69 -0
- package/scripts/windows-cleanup.ps1 +31 -0
- package/.eslintrc.json +0 -24
- package/dist/cli/dev.js +0 -24746
- package/src/cli/dev.ts +0 -946
- package/src/lib/agent-loop.ts +0 -552
- package/src/lib/benchmark-runner.ts +0 -431
- package/src/lib/code-act-agent.ts +0 -378
- package/src/lib/config.ts +0 -163
- package/src/lib/editor.ts +0 -395
- package/src/lib/function-calling.ts +0 -318
- package/src/lib/mcp-client.ts +0 -259
- package/src/lib/peer-agent-network.ts +0 -584
- package/src/lib/swarm-runner.ts +0 -389
- package/src/lib/unified-workspace.ts +0 -435
- package/test-swarm/file1.js +0 -6
- package/test-swarm/file2.ts +0 -12
- package/test-swarm/file3.py +0 -15
- package/test-swarm/file4.md +0 -13
- package/test-swarm/file5.json +0 -12
- package/test-swarm-demo.sh +0 -22
- package/tests/browser-integration.test.ts +0 -242
- package/tests/code-act-agent.test.ts +0 -305
- package/tests/editor.test.ts +0 -223
- package/tests/fixtures/sample-code.js +0 -13
- package/tests/fixtures/sample-code.py +0 -28
- package/tests/fixtures/sample-code.ts +0 -22
- package/tests/mcp-client.test.ts +0 -238
- package/tests/peer-agent-network.test.ts +0 -340
- package/tests/swarm-runner.test.ts +0 -301
- package/tests/swe-bench.test.ts +0 -357
- package/tsconfig.cli.json +0 -25
- package/tsconfig.json +0 -35
- package/vitest.config.ts +0 -37
package/src/lib/agent-loop.ts
DELETED
|
@@ -1,552 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'events';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { FunctionCallingSystem, FunctionCall } from './function-calling';
|
|
4
|
-
import { MCPClient, MCPSession } from './mcp-client';
|
|
5
|
-
|
|
6
|
-
export interface LLMProvider {
|
|
7
|
-
name: string;
|
|
8
|
-
type: 'openai' | 'anthropic' | 'local' | 'hanzo-app';
|
|
9
|
-
apiKey?: string;
|
|
10
|
-
baseUrl?: string;
|
|
11
|
-
model: string;
|
|
12
|
-
supportsTools: boolean;
|
|
13
|
-
supportsStreaming: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface AgentLoopConfig {
|
|
17
|
-
provider: LLMProvider;
|
|
18
|
-
maxIterations: number;
|
|
19
|
-
enableMCP: boolean;
|
|
20
|
-
enableBrowser: boolean;
|
|
21
|
-
enableSwarm: boolean;
|
|
22
|
-
streamOutput: boolean;
|
|
23
|
-
confirmActions: boolean;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface AgentMessage {
|
|
27
|
-
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
28
|
-
content: string;
|
|
29
|
-
toolCalls?: FunctionCall[];
|
|
30
|
-
toolResults?: any[];
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export class ConfigurableAgentLoop extends EventEmitter {
|
|
34
|
-
private config: AgentLoopConfig;
|
|
35
|
-
private functionCalling: FunctionCallingSystem;
|
|
36
|
-
private mcpClient: MCPClient;
|
|
37
|
-
private messages: AgentMessage[] = [];
|
|
38
|
-
private iterations: number = 0;
|
|
39
|
-
|
|
40
|
-
constructor(config: AgentLoopConfig) {
|
|
41
|
-
super();
|
|
42
|
-
this.config = config;
|
|
43
|
-
this.functionCalling = new FunctionCallingSystem();
|
|
44
|
-
this.mcpClient = new MCPClient();
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Get available LLM providers
|
|
48
|
-
static getAvailableProviders(): LLMProvider[] {
|
|
49
|
-
const providers: LLMProvider[] = [];
|
|
50
|
-
|
|
51
|
-
// Check for API keys
|
|
52
|
-
if (process.env.ANTHROPIC_API_KEY) {
|
|
53
|
-
providers.push({
|
|
54
|
-
name: 'Claude (Anthropic)',
|
|
55
|
-
type: 'anthropic',
|
|
56
|
-
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
57
|
-
model: 'claude-3-opus-20240229',
|
|
58
|
-
supportsTools: true,
|
|
59
|
-
supportsStreaming: true
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (process.env.OPENAI_API_KEY) {
|
|
64
|
-
providers.push({
|
|
65
|
-
name: 'GPT-4 (OpenAI)',
|
|
66
|
-
type: 'openai',
|
|
67
|
-
apiKey: process.env.OPENAI_API_KEY,
|
|
68
|
-
model: 'gpt-4-turbo-preview',
|
|
69
|
-
supportsTools: true,
|
|
70
|
-
supportsStreaming: true
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Check for local Hanzo App
|
|
75
|
-
if (process.env.HANZO_APP_URL || this.isHanzoAppRunning()) {
|
|
76
|
-
providers.push({
|
|
77
|
-
name: 'Hanzo Local AI',
|
|
78
|
-
type: 'hanzo-app',
|
|
79
|
-
baseUrl: process.env.HANZO_APP_URL || 'http://localhost:8080',
|
|
80
|
-
model: 'hanzo-zen',
|
|
81
|
-
supportsTools: true,
|
|
82
|
-
supportsStreaming: false
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Check for other local models
|
|
87
|
-
if (process.env.LOCAL_LLM_URL) {
|
|
88
|
-
providers.push({
|
|
89
|
-
name: 'Local LLM',
|
|
90
|
-
type: 'local',
|
|
91
|
-
baseUrl: process.env.LOCAL_LLM_URL,
|
|
92
|
-
model: process.env.LOCAL_LLM_MODEL || 'llama2',
|
|
93
|
-
supportsTools: false,
|
|
94
|
-
supportsStreaming: true
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return providers;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private static isHanzoAppRunning(): boolean {
|
|
102
|
-
// Check if Hanzo App is running locally
|
|
103
|
-
try {
|
|
104
|
-
const { execSync } = require('child_process');
|
|
105
|
-
execSync('curl -s http://localhost:8080/health', { stdio: 'ignore' });
|
|
106
|
-
return true;
|
|
107
|
-
} catch {
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Initialize tools and connections
|
|
113
|
-
async initialize(): Promise<void> {
|
|
114
|
-
console.log(chalk.cyan('\n🔧 Initializing agent loop...\n'));
|
|
115
|
-
|
|
116
|
-
// Initialize MCP tools if enabled
|
|
117
|
-
if (this.config.enableMCP) {
|
|
118
|
-
await this.initializeMCPTools();
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Initialize browser connection if enabled
|
|
122
|
-
if (this.config.enableBrowser) {
|
|
123
|
-
await this.initializeBrowserTools();
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Initialize swarm if enabled
|
|
127
|
-
if (this.config.enableSwarm) {
|
|
128
|
-
await this.initializeSwarmTools();
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
console.log(chalk.green('✓ Agent loop initialized\n'));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
private async initializeMCPTools(): Promise<void> {
|
|
135
|
-
console.log(chalk.gray('Loading MCP tools...'));
|
|
136
|
-
|
|
137
|
-
// Load configured MCP servers from config file
|
|
138
|
-
const mcpConfig = await this.loadMCPConfig();
|
|
139
|
-
|
|
140
|
-
for (const server of mcpConfig.servers) {
|
|
141
|
-
try {
|
|
142
|
-
console.log(chalk.gray(` Connecting to ${server.name}...`));
|
|
143
|
-
const session = await this.mcpClient.connect(server);
|
|
144
|
-
await this.functionCalling.registerMCPServer(server.name, session);
|
|
145
|
-
console.log(chalk.green(` ✓ Connected to ${server.name} (${session.tools.length} tools)`));
|
|
146
|
-
} catch (error) {
|
|
147
|
-
console.log(chalk.yellow(` ⚠ Failed to connect to ${server.name}`));
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
private async initializeBrowserTools(): Promise<void> {
|
|
153
|
-
console.log(chalk.gray('Connecting to browser...'));
|
|
154
|
-
|
|
155
|
-
// Check for Hanzo Browser Extension
|
|
156
|
-
if (await this.checkBrowserExtension()) {
|
|
157
|
-
console.log(chalk.green(' ✓ Connected to Hanzo Browser Extension'));
|
|
158
|
-
this.registerBrowserTools('extension');
|
|
159
|
-
}
|
|
160
|
-
// Check for Hanzo Browser
|
|
161
|
-
else if (await this.checkHanzoBrowser()) {
|
|
162
|
-
console.log(chalk.green(' ✓ Connected to Hanzo Browser'));
|
|
163
|
-
this.registerBrowserTools('browser');
|
|
164
|
-
} else {
|
|
165
|
-
console.log(chalk.yellow(' ⚠ No browser connection available'));
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
private async checkBrowserExtension(): Promise<boolean> {
|
|
170
|
-
// Check if browser extension is available via WebSocket
|
|
171
|
-
try {
|
|
172
|
-
const ws = new (require('ws'))('ws://localhost:9222/hanzo-extension');
|
|
173
|
-
return new Promise((resolve) => {
|
|
174
|
-
ws.on('open', () => {
|
|
175
|
-
ws.close();
|
|
176
|
-
resolve(true);
|
|
177
|
-
});
|
|
178
|
-
ws.on('error', () => resolve(false));
|
|
179
|
-
setTimeout(() => {
|
|
180
|
-
ws.close();
|
|
181
|
-
resolve(false);
|
|
182
|
-
}, 1000);
|
|
183
|
-
});
|
|
184
|
-
} catch {
|
|
185
|
-
return false;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
private async checkHanzoBrowser(): Promise<boolean> {
|
|
190
|
-
// Check if Hanzo Browser is running
|
|
191
|
-
try {
|
|
192
|
-
const response = await fetch('http://localhost:9223/status');
|
|
193
|
-
return response.ok;
|
|
194
|
-
} catch {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
private registerBrowserTools(type: 'extension' | 'browser'): void {
|
|
200
|
-
// Register browser automation tools
|
|
201
|
-
const browserTools = [
|
|
202
|
-
{
|
|
203
|
-
name: 'browser_navigate',
|
|
204
|
-
description: 'Navigate to a URL in the browser',
|
|
205
|
-
parameters: {
|
|
206
|
-
type: 'object',
|
|
207
|
-
properties: {
|
|
208
|
-
url: { type: 'string', description: 'URL to navigate to' }
|
|
209
|
-
},
|
|
210
|
-
required: ['url']
|
|
211
|
-
},
|
|
212
|
-
handler: async (args: any) => this.browserNavigate(args.url)
|
|
213
|
-
},
|
|
214
|
-
{
|
|
215
|
-
name: 'browser_click',
|
|
216
|
-
description: 'Click on an element in the browser',
|
|
217
|
-
parameters: {
|
|
218
|
-
type: 'object',
|
|
219
|
-
properties: {
|
|
220
|
-
selector: { type: 'string', description: 'CSS selector or element ID' }
|
|
221
|
-
},
|
|
222
|
-
required: ['selector']
|
|
223
|
-
},
|
|
224
|
-
handler: async (args: any) => this.browserClick(args.selector)
|
|
225
|
-
},
|
|
226
|
-
{
|
|
227
|
-
name: 'browser_screenshot',
|
|
228
|
-
description: 'Take a screenshot of the current page',
|
|
229
|
-
parameters: {
|
|
230
|
-
type: 'object',
|
|
231
|
-
properties: {
|
|
232
|
-
fullPage: { type: 'boolean', description: 'Capture full page' }
|
|
233
|
-
}
|
|
234
|
-
},
|
|
235
|
-
handler: async (args: any) => this.browserScreenshot(args.fullPage)
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
name: 'browser_fill',
|
|
239
|
-
description: 'Fill a form field in the browser',
|
|
240
|
-
parameters: {
|
|
241
|
-
type: 'object',
|
|
242
|
-
properties: {
|
|
243
|
-
selector: { type: 'string', description: 'CSS selector' },
|
|
244
|
-
value: { type: 'string', description: 'Value to fill' }
|
|
245
|
-
},
|
|
246
|
-
required: ['selector', 'value']
|
|
247
|
-
},
|
|
248
|
-
handler: async (args: any) => this.browserFill(args.selector, args.value)
|
|
249
|
-
}
|
|
250
|
-
];
|
|
251
|
-
|
|
252
|
-
browserTools.forEach(tool => this.functionCalling.registerTool(tool));
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
private async initializeSwarmTools(): Promise<void> {
|
|
256
|
-
console.log(chalk.gray('Initializing swarm tools...'));
|
|
257
|
-
|
|
258
|
-
// Register swarm coordination tools
|
|
259
|
-
this.functionCalling.registerTool({
|
|
260
|
-
name: 'spawn_agent',
|
|
261
|
-
description: 'Spawn a new agent for a specific task',
|
|
262
|
-
parameters: {
|
|
263
|
-
type: 'object',
|
|
264
|
-
properties: {
|
|
265
|
-
task: { type: 'string', description: 'Task for the agent' },
|
|
266
|
-
agentType: { type: 'string', enum: ['claude-code', 'aider', 'openhands'] }
|
|
267
|
-
},
|
|
268
|
-
required: ['task']
|
|
269
|
-
},
|
|
270
|
-
handler: async (args: any) => this.spawnAgent(args.task, args.agentType)
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
this.functionCalling.registerTool({
|
|
274
|
-
name: 'delegate_to_swarm',
|
|
275
|
-
description: 'Delegate multiple tasks to agent swarm',
|
|
276
|
-
parameters: {
|
|
277
|
-
type: 'object',
|
|
278
|
-
properties: {
|
|
279
|
-
tasks: {
|
|
280
|
-
type: 'array',
|
|
281
|
-
items: { type: 'string' },
|
|
282
|
-
description: 'List of tasks to delegate'
|
|
283
|
-
}
|
|
284
|
-
},
|
|
285
|
-
required: ['tasks']
|
|
286
|
-
},
|
|
287
|
-
handler: async (args: any) => this.delegateToSwarm(args.tasks)
|
|
288
|
-
});
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
// Execute agent loop
|
|
292
|
-
async execute(initialPrompt: string): Promise<void> {
|
|
293
|
-
console.log(chalk.cyan(`\n🤖 Starting agent loop with ${this.config.provider.name}\n`));
|
|
294
|
-
|
|
295
|
-
// Add system message
|
|
296
|
-
this.messages.push({
|
|
297
|
-
role: 'system',
|
|
298
|
-
content: this.getSystemPrompt()
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
// Add user message
|
|
302
|
-
this.messages.push({
|
|
303
|
-
role: 'user',
|
|
304
|
-
content: initialPrompt
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
// Main agent loop
|
|
308
|
-
while (this.iterations < this.config.maxIterations) {
|
|
309
|
-
this.iterations++;
|
|
310
|
-
console.log(chalk.blue(`\n▶ Iteration ${this.iterations}`));
|
|
311
|
-
|
|
312
|
-
try {
|
|
313
|
-
// Get LLM response
|
|
314
|
-
const response = await this.callLLM();
|
|
315
|
-
|
|
316
|
-
// Process response
|
|
317
|
-
if (response.toolCalls && response.toolCalls.length > 0) {
|
|
318
|
-
// Execute tool calls
|
|
319
|
-
const results = await this.executeToolCalls(response.toolCalls);
|
|
320
|
-
|
|
321
|
-
// Add tool results to messages
|
|
322
|
-
this.messages.push({
|
|
323
|
-
role: 'tool',
|
|
324
|
-
content: JSON.stringify(results),
|
|
325
|
-
toolResults: results
|
|
326
|
-
});
|
|
327
|
-
} else {
|
|
328
|
-
// No more tool calls, task complete
|
|
329
|
-
console.log(chalk.green('\n✅ Task completed'));
|
|
330
|
-
break;
|
|
331
|
-
}
|
|
332
|
-
} catch (error) {
|
|
333
|
-
console.error(chalk.red(`Error in iteration ${this.iterations}: ${error}`));
|
|
334
|
-
this.emit('error', error);
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (this.iterations >= this.config.maxIterations) {
|
|
340
|
-
console.log(chalk.yellow('\n⚠ Maximum iterations reached'));
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
private getSystemPrompt(): string {
|
|
345
|
-
const tools = this.functionCalling.getAvailableTools();
|
|
346
|
-
|
|
347
|
-
return `You are an AI assistant with access to various tools. You can:
|
|
348
|
-
- Edit files using view_file, create_file, str_replace
|
|
349
|
-
- Run commands using run_command
|
|
350
|
-
- Search files using search_files
|
|
351
|
-
- List directories using list_directory
|
|
352
|
-
${this.config.enableBrowser ? '- Control the browser using browser_* tools' : ''}
|
|
353
|
-
${this.config.enableSwarm ? '- Spawn agents and delegate tasks using swarm tools' : ''}
|
|
354
|
-
${this.config.enableMCP ? '- Use MCP tools for extended functionality' : ''}
|
|
355
|
-
|
|
356
|
-
Available tools: ${tools.map(t => t.name).join(', ')}
|
|
357
|
-
|
|
358
|
-
Always use tools to accomplish tasks. Think step by step.`;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
private async callLLM(): Promise<AgentMessage> {
|
|
362
|
-
const { provider } = this.config;
|
|
363
|
-
|
|
364
|
-
switch (provider.type) {
|
|
365
|
-
case 'anthropic':
|
|
366
|
-
return this.callAnthropic();
|
|
367
|
-
case 'openai':
|
|
368
|
-
return this.callOpenAI();
|
|
369
|
-
case 'hanzo-app':
|
|
370
|
-
return this.callHanzoApp();
|
|
371
|
-
case 'local':
|
|
372
|
-
return this.callLocalLLM();
|
|
373
|
-
default:
|
|
374
|
-
throw new Error(`Unknown provider type: ${provider.type}`);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
private async callAnthropic(): Promise<AgentMessage> {
|
|
379
|
-
// Implementation for Anthropic Claude
|
|
380
|
-
console.log(chalk.gray('Calling Claude...'));
|
|
381
|
-
|
|
382
|
-
// This is a simplified version - in production you'd use the actual API
|
|
383
|
-
const tools = this.functionCalling.getAllToolSchemas();
|
|
384
|
-
|
|
385
|
-
// Simulate API call
|
|
386
|
-
const response = {
|
|
387
|
-
role: 'assistant' as const,
|
|
388
|
-
content: 'I will help you with this task.',
|
|
389
|
-
toolCalls: [
|
|
390
|
-
{
|
|
391
|
-
id: 'call_1',
|
|
392
|
-
name: 'view_file',
|
|
393
|
-
arguments: { path: 'package.json' }
|
|
394
|
-
}
|
|
395
|
-
]
|
|
396
|
-
};
|
|
397
|
-
|
|
398
|
-
this.messages.push(response);
|
|
399
|
-
return response;
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
private async callOpenAI(): Promise<AgentMessage> {
|
|
403
|
-
// Implementation for OpenAI
|
|
404
|
-
console.log(chalk.gray('Calling GPT-4...'));
|
|
405
|
-
|
|
406
|
-
// Similar to Anthropic but with OpenAI API format
|
|
407
|
-
const response = {
|
|
408
|
-
role: 'assistant' as const,
|
|
409
|
-
content: 'I will analyze and complete this task.',
|
|
410
|
-
toolCalls: []
|
|
411
|
-
};
|
|
412
|
-
|
|
413
|
-
this.messages.push(response);
|
|
414
|
-
return response;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
private async callHanzoApp(): Promise<AgentMessage> {
|
|
418
|
-
// Implementation for local Hanzo App
|
|
419
|
-
console.log(chalk.gray('Calling Hanzo Local AI...'));
|
|
420
|
-
|
|
421
|
-
const response = await fetch(`${this.config.provider.baseUrl}/chat`, {
|
|
422
|
-
method: 'POST',
|
|
423
|
-
headers: { 'Content-Type': 'application/json' },
|
|
424
|
-
body: JSON.stringify({
|
|
425
|
-
messages: this.messages,
|
|
426
|
-
tools: this.functionCalling.getAllToolSchemas()
|
|
427
|
-
})
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
const data = await response.json();
|
|
431
|
-
this.messages.push(data);
|
|
432
|
-
return data;
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
private async callLocalLLM(): Promise<AgentMessage> {
|
|
436
|
-
// Implementation for generic local LLM
|
|
437
|
-
console.log(chalk.gray('Calling Local LLM...'));
|
|
438
|
-
|
|
439
|
-
// Local LLMs might not support tools, so we use a different approach
|
|
440
|
-
const response = {
|
|
441
|
-
role: 'assistant' as const,
|
|
442
|
-
content: 'Processing your request...',
|
|
443
|
-
toolCalls: []
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
this.messages.push(response);
|
|
447
|
-
return response;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
private async executeToolCalls(calls: FunctionCall[]): Promise<any[]> {
|
|
451
|
-
if (this.config.confirmActions) {
|
|
452
|
-
console.log(chalk.yellow('\n⚠ Tool calls requested:'));
|
|
453
|
-
calls.forEach(call => {
|
|
454
|
-
console.log(` - ${call.name}(${JSON.stringify(call.arguments)})`);
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
const { confirm } = await require('inquirer').prompt([{
|
|
458
|
-
type: 'confirm',
|
|
459
|
-
name: 'confirm',
|
|
460
|
-
message: 'Execute these actions?',
|
|
461
|
-
default: true
|
|
462
|
-
}]);
|
|
463
|
-
|
|
464
|
-
if (!confirm) {
|
|
465
|
-
throw new Error('User cancelled tool execution');
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
return this.functionCalling.callFunctions(calls);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
// Browser tool implementations
|
|
473
|
-
private async browserNavigate(url: string): Promise<any> {
|
|
474
|
-
console.log(chalk.gray(`Navigating to ${url}...`));
|
|
475
|
-
// Implementation would connect to browser
|
|
476
|
-
return { success: true, url };
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
private async browserClick(selector: string): Promise<any> {
|
|
480
|
-
console.log(chalk.gray(`Clicking ${selector}...`));
|
|
481
|
-
return { success: true, selector };
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
private async browserScreenshot(fullPage: boolean = false): Promise<any> {
|
|
485
|
-
console.log(chalk.gray(`Taking screenshot (fullPage: ${fullPage})...`));
|
|
486
|
-
return { success: true, screenshot: 'base64_image_data' };
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
private async browserFill(selector: string, value: string): Promise<any> {
|
|
490
|
-
console.log(chalk.gray(`Filling ${selector} with "${value}"...`));
|
|
491
|
-
return { success: true, selector, value };
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Swarm tool implementations
|
|
495
|
-
private async spawnAgent(task: string, agentType?: string): Promise<any> {
|
|
496
|
-
console.log(chalk.gray(`Spawning ${agentType || 'default'} agent for: ${task}`));
|
|
497
|
-
return { success: true, agentId: `agent-${Date.now()}`, task };
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
private async delegateToSwarm(tasks: string[]): Promise<any> {
|
|
501
|
-
console.log(chalk.gray(`Delegating ${tasks.length} tasks to swarm...`));
|
|
502
|
-
return { success: true, tasks, status: 'delegated' };
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
// Load MCP configuration
|
|
506
|
-
private async loadMCPConfig(): Promise<{ servers: any[] }> {
|
|
507
|
-
const fs = require('fs');
|
|
508
|
-
const path = require('path');
|
|
509
|
-
const os = require('os');
|
|
510
|
-
|
|
511
|
-
// Check multiple locations for MCP config
|
|
512
|
-
const configPaths = [
|
|
513
|
-
path.join(process.cwd(), '.mcp.json'),
|
|
514
|
-
path.join(os.homedir(), '.config', 'hanzo-dev', 'mcp.json'),
|
|
515
|
-
path.join(os.homedir(), '.hanzo', 'mcp.json')
|
|
516
|
-
];
|
|
517
|
-
|
|
518
|
-
for (const configPath of configPaths) {
|
|
519
|
-
if (fs.existsSync(configPath)) {
|
|
520
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
521
|
-
return JSON.parse(content);
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// Default MCP servers
|
|
526
|
-
return {
|
|
527
|
-
servers: [
|
|
528
|
-
{
|
|
529
|
-
name: 'filesystem',
|
|
530
|
-
command: 'npx',
|
|
531
|
-
args: ['@modelcontextprotocol/server-filesystem'],
|
|
532
|
-
env: { MCP_ALLOWED_PATHS: process.cwd() }
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
name: 'git',
|
|
536
|
-
command: 'npx',
|
|
537
|
-
args: ['@modelcontextprotocol/server-git']
|
|
538
|
-
}
|
|
539
|
-
]
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
// Get current configuration
|
|
544
|
-
getConfig(): AgentLoopConfig {
|
|
545
|
-
return this.config;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Update configuration
|
|
549
|
-
updateConfig(updates: Partial<AgentLoopConfig>): void {
|
|
550
|
-
this.config = { ...this.config, ...updates };
|
|
551
|
-
}
|
|
552
|
-
}
|