ruvector 0.1.90 → 0.1.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js CHANGED
@@ -7376,6 +7376,208 @@ edgeNetCmd.command('status')
7376
7376
  }
7377
7377
  });
7378
7378
 
7379
+ // ============================================
7380
+ // REAL AGENT COMMANDS (Actual LLM Execution)
7381
+ // ============================================
7382
+
7383
+ const agentCmd = program.command('agent').description('Real AI agent execution with LLM APIs (requires ANTHROPIC_API_KEY or OPENAI_API_KEY)');
7384
+
7385
+ agentCmd.command('run')
7386
+ .description('Execute a task with a real AI agent (calls actual LLM API)')
7387
+ .argument('<type>', 'Agent type: researcher, coder, reviewer, tester, analyst, optimizer, coordinator, embedder')
7388
+ .argument('<task>', 'Task description for the agent to execute')
7389
+ .option('-p, --provider <provider>', 'LLM provider: anthropic or openai', 'anthropic')
7390
+ .option('-m, --model <model>', 'Model tier: fast, balanced, powerful', 'balanced')
7391
+ .option('-f, --files <files...>', 'Files to include as context')
7392
+ .option('-c, --context <context>', 'Additional context string')
7393
+ .option('--max-tokens <tokens>', 'Maximum tokens in response', '4096')
7394
+ .option('--relay <url>', 'Relay server URL for sync')
7395
+ .option('--json', 'Output as JSON')
7396
+ .action(async (type, task, opts) => {
7397
+ const spinner = ora('Initializing real agent...').start();
7398
+
7399
+ // Check for API key
7400
+ const apiKey = process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
7401
+ if (!apiKey && type !== 'embedder') {
7402
+ spinner.fail('No API key found');
7403
+ console.log(chalk.red('\nāŒ Real agent execution requires an API key.\n'));
7404
+ console.log(chalk.bold('Set one of these environment variables:'));
7405
+ console.log(chalk.cyan(' export ANTHROPIC_API_KEY=your-key-here'));
7406
+ console.log(chalk.cyan(' export OPENAI_API_KEY=your-key-here'));
7407
+ console.log(chalk.dim('\nGet an API key:'));
7408
+ console.log(chalk.dim(' Anthropic: https://console.anthropic.com/'));
7409
+ console.log(chalk.dim(' OpenAI: https://platform.openai.com/api-keys\n'));
7410
+ return;
7411
+ }
7412
+
7413
+ try {
7414
+ // Try to load real-agents module
7415
+ let RealAgentManager;
7416
+ try {
7417
+ const realAgents = await import('@ruvector/edge-net/real-agents');
7418
+ RealAgentManager = realAgents.RealAgentManager;
7419
+ } catch (e) {
7420
+ // Fallback to local path for development
7421
+ try {
7422
+ const realAgentsPath = path.resolve(__dirname, '../../../../examples/edge-net/pkg/real-agents.js');
7423
+ const realAgents = await import(realAgentsPath);
7424
+ RealAgentManager = realAgents.RealAgentManager;
7425
+ } catch (e2) {
7426
+ spinner.fail('Real agents module not found');
7427
+ console.log(chalk.yellow('\nInstall @ruvector/edge-net for real agent execution:'));
7428
+ console.log(chalk.cyan(' npm install @ruvector/edge-net\n'));
7429
+ return;
7430
+ }
7431
+ }
7432
+
7433
+ // Determine provider from API key if not specified
7434
+ const provider = opts.provider || (process.env.ANTHROPIC_API_KEY ? 'anthropic' : 'openai');
7435
+
7436
+ spinner.text = `Spawning ${type} agent (${provider})...`;
7437
+
7438
+ // Initialize manager
7439
+ const manager = new RealAgentManager({
7440
+ provider,
7441
+ apiKey,
7442
+ relayUrl: opts.relay,
7443
+ enableSync: !!opts.relay,
7444
+ });
7445
+ await manager.initialize();
7446
+
7447
+ // Spawn agent
7448
+ const agent = await manager.spawn(type, {
7449
+ provider,
7450
+ model: opts.model,
7451
+ });
7452
+
7453
+ spinner.text = `Executing task with ${type} agent...`;
7454
+
7455
+ // Build context
7456
+ const context = {
7457
+ model: opts.model,
7458
+ files: opts.files || [],
7459
+ additionalContext: opts.context,
7460
+ maxTokens: parseInt(opts.maxTokens) || 4096,
7461
+ };
7462
+
7463
+ // Execute task
7464
+ const startTime = Date.now();
7465
+ const result = await agent.execute(task, context);
7466
+ const duration = Date.now() - startTime;
7467
+
7468
+ spinner.succeed(`Task completed in ${(duration / 1000).toFixed(2)}s`);
7469
+
7470
+ if (opts.json) {
7471
+ console.log(JSON.stringify({
7472
+ success: true,
7473
+ agentId: agent.id,
7474
+ type,
7475
+ provider,
7476
+ model: result.model,
7477
+ duration,
7478
+ result,
7479
+ }, null, 2));
7480
+ } else {
7481
+ console.log(chalk.bold.cyan(`\nšŸ¤– Real Agent Execution Complete\n`));
7482
+ console.log(`${chalk.cyan('Agent ID:')} ${agent.id}`);
7483
+ console.log(`${chalk.cyan('Type:')} ${type}`);
7484
+ console.log(`${chalk.cyan('Provider:')} ${provider}`);
7485
+ console.log(`${chalk.cyan('Model:')} ${result.model}`);
7486
+ console.log(`${chalk.cyan('Duration:')} ${(duration / 1000).toFixed(2)}s`);
7487
+
7488
+ if (agent.cost.inputTokens || agent.cost.outputTokens) {
7489
+ console.log(`${chalk.cyan('Tokens:')} ${agent.cost.inputTokens} in / ${agent.cost.outputTokens} out`);
7490
+ }
7491
+
7492
+ console.log(chalk.bold('\nšŸ“ Response:\n'));
7493
+ console.log(result.content || JSON.stringify(result, null, 2));
7494
+ console.log();
7495
+ }
7496
+
7497
+ await manager.close();
7498
+
7499
+ } catch (e) {
7500
+ spinner.fail(`Agent execution failed: ${e.message}`);
7501
+ if (e.message.includes('401') || e.message.includes('Unauthorized')) {
7502
+ console.log(chalk.yellow('\nCheck your API key is valid and has sufficient credits.'));
7503
+ }
7504
+ }
7505
+ });
7506
+
7507
+ agentCmd.command('types')
7508
+ .description('List available agent types')
7509
+ .action(() => {
7510
+ console.log(chalk.bold.cyan('\nšŸ¤– Available Real Agent Types\n'));
7511
+
7512
+ const types = [
7513
+ { type: 'researcher', desc: 'Analyze, search, summarize information', cost: '~$0.01-0.05/task' },
7514
+ { type: 'coder', desc: 'Write, refactor, debug code', cost: '~$0.02-0.10/task' },
7515
+ { type: 'reviewer', desc: 'Review code quality and security', cost: '~$0.01-0.05/task' },
7516
+ { type: 'tester', desc: 'Write tests and validate functionality', cost: '~$0.01-0.05/task' },
7517
+ { type: 'analyst', desc: 'Analyze data and generate reports', cost: '~$0.01-0.05/task' },
7518
+ { type: 'optimizer', desc: 'Profile and improve performance', cost: '~$0.02-0.10/task' },
7519
+ { type: 'coordinator', desc: 'Orchestrate workflows and tasks', cost: '~$0.02-0.10/task' },
7520
+ { type: 'embedder', desc: 'Generate semantic embeddings (no API key needed)', cost: 'Free (local)' },
7521
+ ];
7522
+
7523
+ types.forEach(t => {
7524
+ console.log(` ${chalk.green('•')} ${chalk.bold(t.type.padEnd(12))} ${t.desc}`);
7525
+ console.log(` ${chalk.dim('Estimated cost: ' + t.cost)}`);
7526
+ });
7527
+
7528
+ console.log(chalk.bold('\nšŸ“‹ Model Tiers:\n'));
7529
+ console.log(` ${chalk.cyan('fast')} - Quick responses, lower cost (Haiku/GPT-4o-mini)`);
7530
+ console.log(` ${chalk.cyan('balanced')} - Good quality/speed balance (Sonnet/GPT-4o)`);
7531
+ console.log(` ${chalk.cyan('powerful')} - Best quality, higher cost (Opus/GPT-4-turbo)`);
7532
+
7533
+ console.log(chalk.bold('\nšŸ”§ Example:\n'));
7534
+ console.log(chalk.dim(' export ANTHROPIC_API_KEY=your-key'));
7535
+ console.log(chalk.cyan(' ruvector agent run coder "Write a function to validate emails" -m fast'));
7536
+ console.log();
7537
+ });
7538
+
7539
+ agentCmd.command('balance')
7540
+ .description('Show rUv balance and sync status')
7541
+ .option('--relay <url>', 'Relay server URL', 'ws://localhost:8080')
7542
+ .action(async (opts) => {
7543
+ const spinner = ora('Connecting to relay...').start();
7544
+
7545
+ try {
7546
+ let RelaySyncClient;
7547
+ try {
7548
+ const realAgents = await import('@ruvector/edge-net/real-agents');
7549
+ RelaySyncClient = realAgents.RelaySyncClient;
7550
+ } catch (e) {
7551
+ const realAgentsPath = path.resolve(__dirname, '../../../../examples/edge-net/pkg/real-agents.js');
7552
+ const realAgents = await import(realAgentsPath);
7553
+ RelaySyncClient = realAgents.RelaySyncClient;
7554
+ }
7555
+
7556
+ const client = new RelaySyncClient({ relayUrl: opts.relay });
7557
+
7558
+ await Promise.race([
7559
+ client.connect(),
7560
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Connection timeout')), 5000)),
7561
+ ]);
7562
+
7563
+ spinner.succeed('Connected to relay');
7564
+
7565
+ console.log(chalk.bold.cyan('\nšŸ’° rUv Balance\n'));
7566
+ console.log(`${chalk.cyan('Balance:')} ${client.getBalance()} rUv`);
7567
+ console.log(`${chalk.cyan('Relay:')} ${opts.relay}`);
7568
+ console.log(`${chalk.cyan('Node ID:')} ${client.nodeId}`);
7569
+ console.log(`${chalk.cyan('Status:')} ${chalk.green('Connected')}`);
7570
+ console.log();
7571
+
7572
+ client.close();
7573
+
7574
+ } catch (e) {
7575
+ spinner.fail(`Connection failed: ${e.message}`);
7576
+ console.log(chalk.dim('\nMake sure the relay server is running:'));
7577
+ console.log(chalk.cyan(' cd examples/edge-net/relay && node index.js\n'));
7578
+ }
7579
+ });
7580
+
7379
7581
  // MCP Server command
7380
7582
  const mcpCmd = program.command('mcp').description('MCP (Model Context Protocol) server for Claude Code integration');
7381
7583
 
package/bin/mcp-server.js CHANGED
@@ -1124,6 +1124,37 @@ const TOOLS = [
1124
1124
  properties: {},
1125
1125
  required: []
1126
1126
  }
1127
+ },
1128
+ {
1129
+ name: 'agent_execute',
1130
+ description: 'REAL agent execution that calls actual LLM APIs (Anthropic Claude or OpenAI). Requires ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable.',
1131
+ inputSchema: {
1132
+ type: 'object',
1133
+ properties: {
1134
+ type: {
1135
+ type: 'string',
1136
+ description: 'Agent type',
1137
+ enum: ['researcher', 'coder', 'reviewer', 'tester', 'analyst', 'optimizer', 'coordinator', 'embedder']
1138
+ },
1139
+ task: { type: 'string', description: 'Task for the agent to execute' },
1140
+ provider: { type: 'string', enum: ['anthropic', 'openai'], description: 'LLM provider (auto-detected from API key)' },
1141
+ model: { type: 'string', enum: ['fast', 'balanced', 'powerful'], default: 'balanced', description: 'Model tier' },
1142
+ context: { type: 'string', description: 'Additional context for the agent' },
1143
+ max_tokens: { type: 'number', default: 4096, description: 'Maximum tokens in response' }
1144
+ },
1145
+ required: ['type', 'task']
1146
+ }
1147
+ },
1148
+ {
1149
+ name: 'agent_balance',
1150
+ description: 'Get rUv credit balance from relay server with multi-device sync status',
1151
+ inputSchema: {
1152
+ type: 'object',
1153
+ properties: {
1154
+ relay_url: { type: 'string', description: 'Relay server URL', default: 'ws://localhost:8080' }
1155
+ },
1156
+ required: []
1157
+ }
1127
1158
  }
1128
1159
  ];
1129
1160
 
@@ -2787,6 +2818,162 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2787
2818
  return { content: [{ type: 'text', text: JSON.stringify(status, null, 2) }] };
2788
2819
  }
2789
2820
 
2821
+ case 'agent_execute': {
2822
+ // REAL agent execution with actual LLM API calls
2823
+ const validTypes = ['researcher', 'coder', 'reviewer', 'tester', 'analyst', 'optimizer', 'coordinator', 'embedder'];
2824
+ const validModels = ['fast', 'balanced', 'powerful'];
2825
+
2826
+ const agentType = validTypes.includes(args.type) ? args.type : 'coder';
2827
+ const task = typeof args.task === 'string' ? args.task.slice(0, 10000).trim() : '';
2828
+ const model = validModels.includes(args.model) ? args.model : 'balanced';
2829
+ const maxTokens = Math.min(Math.max(parseInt(args.max_tokens) || 4096, 100), 8192);
2830
+
2831
+ // Check for API key
2832
+ const apiKey = process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
2833
+ if (!apiKey && agentType !== 'embedder') {
2834
+ return {
2835
+ content: [{
2836
+ type: 'text',
2837
+ text: JSON.stringify({
2838
+ success: false,
2839
+ error: 'No API key configured',
2840
+ message: 'Set ANTHROPIC_API_KEY or OPENAI_API_KEY environment variable',
2841
+ help: {
2842
+ anthropic: 'https://console.anthropic.com/',
2843
+ openai: 'https://platform.openai.com/api-keys'
2844
+ }
2845
+ }, null, 2)
2846
+ }],
2847
+ isError: true
2848
+ };
2849
+ }
2850
+
2851
+ try {
2852
+ // Try to load real-agents module
2853
+ let RealAgentManager;
2854
+ try {
2855
+ const realAgents = await import('@ruvector/edge-net/real-agents');
2856
+ RealAgentManager = realAgents.RealAgentManager;
2857
+ } catch (e) {
2858
+ // Fallback to local path for development
2859
+ const realAgentsPath = path.resolve(__dirname, '../../../examples/edge-net/pkg/real-agents.js');
2860
+ const realAgents = await import(realAgentsPath);
2861
+ RealAgentManager = realAgents.RealAgentManager;
2862
+ }
2863
+
2864
+ // Determine provider from API key
2865
+ const provider = args.provider || (process.env.ANTHROPIC_API_KEY ? 'anthropic' : 'openai');
2866
+
2867
+ // Initialize manager
2868
+ const manager = new RealAgentManager({
2869
+ provider,
2870
+ apiKey,
2871
+ });
2872
+ await manager.initialize();
2873
+
2874
+ // Spawn and execute
2875
+ const agent = await manager.spawn(agentType, { provider, model });
2876
+
2877
+ const context = {
2878
+ model,
2879
+ additionalContext: args.context,
2880
+ maxTokens,
2881
+ };
2882
+
2883
+ const startTime = Date.now();
2884
+ const result = await agent.execute(task, context);
2885
+ const duration = Date.now() - startTime;
2886
+
2887
+ await manager.close();
2888
+
2889
+ return {
2890
+ content: [{
2891
+ type: 'text',
2892
+ text: JSON.stringify({
2893
+ success: true,
2894
+ real_execution: true,
2895
+ agent: {
2896
+ id: agent.id,
2897
+ type: agentType,
2898
+ provider,
2899
+ model: result.model
2900
+ },
2901
+ execution: {
2902
+ duration_ms: duration,
2903
+ tokens: agent.cost
2904
+ },
2905
+ response: result.content
2906
+ }, null, 2)
2907
+ }]
2908
+ };
2909
+
2910
+ } catch (execError) {
2911
+ return {
2912
+ content: [{
2913
+ type: 'text',
2914
+ text: JSON.stringify({
2915
+ success: false,
2916
+ error: execError.message,
2917
+ real_execution: true,
2918
+ hint: execError.message.includes('401') ? 'Check your API key is valid' : 'Check error message for details'
2919
+ }, null, 2)
2920
+ }],
2921
+ isError: true
2922
+ };
2923
+ }
2924
+ }
2925
+
2926
+ case 'agent_balance': {
2927
+ const relayUrl = args.relay_url || 'ws://localhost:8080';
2928
+
2929
+ try {
2930
+ // Try to load real-agents module
2931
+ let RelaySyncClient;
2932
+ try {
2933
+ const realAgents = await import('@ruvector/edge-net/real-agents');
2934
+ RelaySyncClient = realAgents.RelaySyncClient;
2935
+ } catch (e) {
2936
+ const realAgentsPath = path.resolve(__dirname, '../../../examples/edge-net/pkg/real-agents.js');
2937
+ const realAgents = await import(realAgentsPath);
2938
+ RelaySyncClient = realAgents.RelaySyncClient;
2939
+ }
2940
+
2941
+ const client = new RelaySyncClient({ relayUrl });
2942
+
2943
+ await Promise.race([
2944
+ client.connect(),
2945
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Connection timeout')), 5000)),
2946
+ ]);
2947
+
2948
+ const balance = {
2949
+ success: true,
2950
+ balance: client.getBalance(),
2951
+ nodeId: client.nodeId,
2952
+ relayUrl,
2953
+ connected: true,
2954
+ ledgerState: client.ledgerState
2955
+ };
2956
+
2957
+ client.close();
2958
+
2959
+ return { content: [{ type: 'text', text: JSON.stringify(balance, null, 2) }] };
2960
+
2961
+ } catch (connError) {
2962
+ return {
2963
+ content: [{
2964
+ type: 'text',
2965
+ text: JSON.stringify({
2966
+ success: false,
2967
+ error: connError.message,
2968
+ relayUrl,
2969
+ hint: 'Start the relay server: cd examples/edge-net/relay && node index.js'
2970
+ }, null, 2)
2971
+ }],
2972
+ isError: true
2973
+ };
2974
+ }
2975
+ }
2976
+
2790
2977
  default:
2791
2978
  return {
2792
2979
  content: [{
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ruvector",
3
- "version": "0.1.90",
3
+ "version": "0.1.91",
4
4
  "description": "High-performance vector database for Node.js with automatic native/WASM fallback",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",