@juspay/neurolink 1.11.2 → 2.0.0
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/CHANGELOG.md +33 -2
- package/README.md +67 -22
- package/dist/cli/commands/mcp.js +1 -1
- package/dist/cli/index.js +60 -9
- package/dist/lib/providers/agent-enhanced-provider.d.ts +20 -0
- package/dist/lib/providers/agent-enhanced-provider.js +243 -6
- package/dist/lib/providers/googleAIStudio.js +4 -2
- package/dist/providers/agent-enhanced-provider.d.ts +20 -0
- package/dist/providers/agent-enhanced-provider.js +244 -7
- package/dist/providers/googleAIStudio.js +4 -2
- package/package.json +47 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
|
-
# [
|
|
1
|
+
# [2.0.0](https://github.com/juspay/neurolink/compare/v1.11.3...v2.0.0) (2025-06-28)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **cli:** add command variations and stream agent support ([5fc4c26](https://github.com/juspay/neurolink/commit/5fc4c26b23bd189be52272521bdd2ca40dd55837))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### BREAKING CHANGES
|
|
10
|
+
|
|
11
|
+
* **cli:** 'generate-text' command is deprecated and will be removed in v2.0
|
|
12
|
+
|
|
13
|
+
## [1.11.3](https://github.com/juspay/neurolink/compare/v1.11.2...v1.11.3) (2025-06-22)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* resolve MCP external tools returning raw JSON instead of human-readable responses ([921a12b](https://github.com/juspay/neurolink/commit/921a12b5b31ca96bbfe3f1db05001ddb84470e14))
|
|
19
|
+
|
|
20
|
+
## [1.11.2](https://github.com/juspay/neurolink/compare/v1.11.1...v1.11.2) (2025-06-22)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
2
24
|
|
|
25
|
+
* **ci:** refactor auto-converted Node.js scripts ([4088888](https://github.com/juspay/neurolink/commit/408888863f8223e64269423412f5c79a35ddfe36))
|
|
26
|
+
|
|
27
|
+
## [1.11.1](https://github.com/juspay/neurolink/compare/v1.11.0...v1.11.1) (2025-06-21)
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
- add backward compatiblity for gemini ([5e84dab](https://github.com/juspay/neurolink/commit/5e84dab598156a5b77d05b343d0d69ecf91f31b0))
|
|
32
|
+
|
|
33
|
+
# [1.11.0](https://github.com/juspay/neurolink/compare/v1.10.0...v1.11.0) (2025-06-21)
|
|
3
34
|
|
|
4
35
|
### Features
|
|
5
36
|
|
|
6
|
-
|
|
37
|
+
- finalize MCP ecosystem and resolve all TypeScript errors ([605d8b2](https://github.com/juspay/neurolink/commit/605d8b2ea10c824077e1379ac47a0c065f0a8095))
|
|
7
38
|
|
|
8
39
|
# [1.10.0](https://github.com/juspay/neurolink/compare/v1.9.0...v1.10.0) (2025-06-21)
|
|
9
40
|
|
package/README.md
CHANGED
|
@@ -15,16 +15,22 @@
|
|
|
15
15
|
|
|
16
16
|
**MAJOR SUCCESS**: All blocking TypeScript compilation errors resolved + Complete CLI MCP integration achieved!
|
|
17
17
|
|
|
18
|
-
✅ **Function Calling Ready**: AI can now execute real filesystem operations, data analysis, and system commands
|
|
19
|
-
✅ **Production Validated**: 23,230+ token MCP context loading confirmed via comprehensive CLI testing
|
|
20
|
-
✅ **Zero Build Errors**: Clean TypeScript compilation after resolving all 13 blocking errors
|
|
21
|
-
✅ **CLI Tool Integration**: Both `generate
|
|
18
|
+
✅ **Function Calling Ready**: AI can now execute real filesystem operations, data analysis, and system commands
|
|
19
|
+
✅ **Production Validated**: 23,230+ token MCP context loading confirmed via comprehensive CLI testing
|
|
20
|
+
✅ **Zero Build Errors**: Clean TypeScript compilation after resolving all 13 blocking errors
|
|
21
|
+
✅ **CLI Tool Integration**: Both `generate`/`gen` and `agent-generate` commands use full MCP capabilities
|
|
22
22
|
✅ **Backward Compatible**: Tools enabled by default with opt-out flag for traditional usage
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
# NEW: AI can now access your filesystem and execute tools
|
|
25
|
+
# NEW: AI can now access your filesystem and execute tools (use preferred commands)
|
|
26
|
+
npx @juspay/neurolink generate "List files in this directory" --provider google-ai
|
|
27
|
+
|
|
28
|
+
# Alternative shorter command
|
|
29
|
+
npx @juspay/neurolink gen "List files in this directory" --provider google-ai
|
|
30
|
+
|
|
31
|
+
# ⚠️ DEPRECATED: generate-text will be removed in v2.0 (use 'generate' or 'gen' instead)
|
|
32
|
+
# This command shows a deprecation warning and is kept for backward compatibility only
|
|
26
33
|
npx @juspay/neurolink generate-text "List files in this directory" --provider google-ai
|
|
27
|
-
# Result: AI uses listDirectory tool and returns actual file listing
|
|
28
34
|
```
|
|
29
35
|
|
|
30
36
|
## 🚀 Quick Start
|
|
@@ -36,7 +42,8 @@ npx @juspay/neurolink generate-text "List files in this directory" --provider go
|
|
|
36
42
|
export GOOGLE_AI_API_KEY="AIza-your-google-ai-api-key"
|
|
37
43
|
|
|
38
44
|
# CLI - No installation required
|
|
39
|
-
npx @juspay/neurolink generate
|
|
45
|
+
npx @juspay/neurolink generate "Hello, AI"
|
|
46
|
+
npx @juspay/neurolink gen "Hello, AI" # Shortest form
|
|
40
47
|
npx @juspay/neurolink status
|
|
41
48
|
```
|
|
42
49
|
|
|
@@ -91,25 +98,31 @@ npx @juspay/neurolink status
|
|
|
91
98
|
- 🌍 **Open Source Models** - Access 100,000+ models via Hugging Face
|
|
92
99
|
- 🇪🇺 **GDPR Compliance** - European data processing with Mistral AI
|
|
93
100
|
|
|
94
|
-
## 🛠️ MCP Integration Status (v1.
|
|
101
|
+
## 🛠️ MCP Integration Status (v1.11.1) ✅ **PRODUCTION READY**
|
|
95
102
|
|
|
96
103
|
| Component | Status | Description |
|
|
97
104
|
| ------------------- | ------------------ | --------------------------------------------------- |
|
|
98
105
|
| Built-in Tools | ✅ **Working** | Time tool, utilities - fully functional |
|
|
99
106
|
| External Discovery | ✅ **Working** | 58+ MCP servers auto-discovered from all AI tools |
|
|
100
107
|
| Tool Execution | ✅ **Working** | Real-time AI tool calling with built-in tools |
|
|
108
|
+
| **External Tools** | ✅ **SOLVED** | **Two-step tool calling fixed - human-readable responses** |
|
|
109
|
+
| **CLI Integration** | ✅ **READY** | **Production-ready AI assistant with external tools** |
|
|
101
110
|
| External Activation | 🔧 **Development** | Discovery complete, activation protocol in progress |
|
|
102
111
|
|
|
103
112
|
### ✅ Quick MCP Test (v1.7.1)
|
|
104
113
|
|
|
105
114
|
```bash
|
|
106
115
|
# Test built-in tools (works immediately)
|
|
107
|
-
npx @juspay/neurolink generate
|
|
108
|
-
|
|
116
|
+
npx @juspay/neurolink generate "What time is it?" --debug
|
|
117
|
+
|
|
118
|
+
# Alternative short form
|
|
119
|
+
npx @juspay/neurolink gen "What time is it?" --debug
|
|
109
120
|
|
|
110
121
|
# Test tool discovery
|
|
111
|
-
npx @juspay/neurolink generate
|
|
112
|
-
|
|
122
|
+
npx @juspay/neurolink generate "What tools do you have access to?" --debug
|
|
123
|
+
|
|
124
|
+
# Alternative short form
|
|
125
|
+
npx @juspay/neurolink gen "What tools do you have access to?" --debug
|
|
113
126
|
|
|
114
127
|
# Test external server discovery
|
|
115
128
|
npx @juspay/neurolink mcp discover --format table
|
|
@@ -132,13 +145,13 @@ NeuroLink now features a revolutionary dynamic model configuration system that e
|
|
|
132
145
|
|
|
133
146
|
```bash
|
|
134
147
|
# Cost optimization - automatically use cheapest model
|
|
135
|
-
npx @juspay/neurolink generate
|
|
148
|
+
npx @juspay/neurolink generate "Hello" --optimize-cost
|
|
136
149
|
|
|
137
150
|
# Capability search - find models with specific features
|
|
138
|
-
npx @juspay/neurolink generate
|
|
151
|
+
npx @juspay/neurolink generate "Describe this image" --capability vision
|
|
139
152
|
|
|
140
153
|
# Model aliases - use friendly names
|
|
141
|
-
npx @juspay/neurolink
|
|
154
|
+
npx @juspay/neurolink gen "Write code" --model best-coding
|
|
142
155
|
|
|
143
156
|
# Test dynamic model server
|
|
144
157
|
npm run model-server # Starts config server on localhost:3001
|
|
@@ -161,14 +174,19 @@ npm run test:dynamic-models # Comprehensive test suite
|
|
|
161
174
|
|
|
162
175
|
```bash
|
|
163
176
|
# Text generation with automatic MCP tool detection (default)
|
|
164
|
-
npx @juspay/neurolink generate
|
|
165
|
-
|
|
177
|
+
npx @juspay/neurolink generate "What time is it?"
|
|
178
|
+
|
|
179
|
+
# Alternative short form
|
|
180
|
+
npx @juspay/neurolink gen "What time is it?"
|
|
166
181
|
|
|
167
182
|
# Disable tools for training-data-only responses
|
|
168
|
-
npx @juspay/neurolink generate
|
|
183
|
+
npx @juspay/neurolink generate "What time is it?" --disable-tools
|
|
184
|
+
|
|
185
|
+
# Real-time streaming with agent support (default)
|
|
186
|
+
npx @juspay/neurolink stream "What time is it?"
|
|
169
187
|
|
|
170
|
-
#
|
|
171
|
-
npx @juspay/neurolink stream "Tell me a story
|
|
188
|
+
# Streaming without tools (traditional mode)
|
|
189
|
+
npx @juspay/neurolink stream "Tell me a story" --disable-tools
|
|
172
190
|
|
|
173
191
|
# Provider diagnostics
|
|
174
192
|
npx @juspay/neurolink status --verbose
|
|
@@ -292,10 +310,37 @@ We welcome contributions! Please see our [Contributing Guidelines](./CONTRIBUTIN
|
|
|
292
310
|
git clone https://github.com/juspay/neurolink
|
|
293
311
|
cd neurolink
|
|
294
312
|
pnpm install
|
|
295
|
-
pnpm
|
|
296
|
-
pnpm
|
|
313
|
+
pnpm setup:complete # One-command setup with all automation
|
|
314
|
+
pnpm test:adaptive # Intelligent testing
|
|
315
|
+
pnpm build:complete # Full build pipeline
|
|
297
316
|
```
|
|
298
317
|
|
|
318
|
+
### New Developer Experience (v2.0)
|
|
319
|
+
|
|
320
|
+
NeuroLink now features **enterprise-grade automation** with 72+ commands:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Environment & Setup (2-minute initialization)
|
|
324
|
+
pnpm setup:complete # Complete project setup
|
|
325
|
+
pnpm env:setup # Safe .env configuration
|
|
326
|
+
pnpm env:backup # Environment backup
|
|
327
|
+
|
|
328
|
+
# Testing & Quality (60-80% faster)
|
|
329
|
+
pnpm test:adaptive # Intelligent test selection
|
|
330
|
+
pnpm test:providers # AI provider validation
|
|
331
|
+
pnpm quality:check # Full quality pipeline
|
|
332
|
+
|
|
333
|
+
# Documentation & Content
|
|
334
|
+
pnpm docs:sync # Cross-file documentation sync
|
|
335
|
+
pnpm content:generate # Automated content creation
|
|
336
|
+
|
|
337
|
+
# Build & Deployment
|
|
338
|
+
pnpm build:complete # 7-phase enterprise pipeline
|
|
339
|
+
pnpm dev:health # System health monitoring
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**[📖 Complete Automation Guide](./docs/CLI-GUIDE.md)** - All 72+ commands and automation features
|
|
343
|
+
|
|
299
344
|
## 📄 License
|
|
300
345
|
|
|
301
346
|
MIT © [Juspay Technologies](https://juspay.in)
|
package/dist/cli/commands/mcp.js
CHANGED
|
@@ -13,7 +13,7 @@ import { unifiedRegistry } from "../../lib/mcp/unified-registry.js";
|
|
|
13
13
|
import { ContextManager } from "../../lib/mcp/context-manager.js";
|
|
14
14
|
import { MCPOrchestrator } from "../../lib/mcp/orchestrator.js";
|
|
15
15
|
import { initializeNeuroLinkMCP } from "../../lib/mcp/initialize.js";
|
|
16
|
-
import { mcpLogger, setGlobalMCPLogLevel
|
|
16
|
+
import { mcpLogger, setGlobalMCPLogLevel } from "../../lib/mcp/logging.js";
|
|
17
17
|
// Default MCP config file location
|
|
18
18
|
const MCP_CONFIG_FILE = path.join(process.cwd(), ".mcp-config.json");
|
|
19
19
|
// Load MCP configuration
|
package/dist/cli/index.js
CHANGED
|
@@ -204,7 +204,7 @@ const cli = yargs(args)
|
|
|
204
204
|
exitProcess(); // Default exit
|
|
205
205
|
})
|
|
206
206
|
// Generate Text Command
|
|
207
|
-
.command(["generate-text <prompt>", "generate <prompt>"], "Generate text using AI providers", (yargsInstance) => yargsInstance
|
|
207
|
+
.command(["generate-text <prompt>", "generate <prompt>", "gen <prompt>"], "Generate text using AI providers", (yargsInstance) => yargsInstance
|
|
208
208
|
.usage("Usage: $0 generate-text <prompt> [options]")
|
|
209
209
|
.positional("prompt", {
|
|
210
210
|
type: "string",
|
|
@@ -266,6 +266,11 @@ const cli = yargs(args)
|
|
|
266
266
|
.example('$0 generate-text "Write a story" --provider openai', "Use specific provider")
|
|
267
267
|
.example('$0 generate-text "What time is it?"', "Use with natural tool integration (default)")
|
|
268
268
|
.example('$0 generate-text "Hello world" --disable-tools', "Use without tool integration"), async (argv) => {
|
|
269
|
+
// Check if generate-text was used specifically (for deprecation warning)
|
|
270
|
+
const usedCommand = argv._[0];
|
|
271
|
+
if (usedCommand === 'generate-text' && !argv.quiet) {
|
|
272
|
+
console.warn(chalk.yellow('⚠️ Warning: "generate-text" is deprecated. Use "generate" or "gen" instead for multimodal support.'));
|
|
273
|
+
}
|
|
269
274
|
let originalConsole = {};
|
|
270
275
|
if (argv.format === "json" && !argv.quiet) {
|
|
271
276
|
// Suppress only if not quiet, as quiet implies no spinners anyway
|
|
@@ -437,7 +442,14 @@ const cli = yargs(args)
|
|
|
437
442
|
default: false,
|
|
438
443
|
description: "Enable debug mode with interleaved logging",
|
|
439
444
|
})
|
|
440
|
-
.
|
|
445
|
+
.option("disable-tools", {
|
|
446
|
+
type: "boolean",
|
|
447
|
+
default: false,
|
|
448
|
+
description: "Disable MCP tool integration (tools enabled by default)",
|
|
449
|
+
})
|
|
450
|
+
.example('$0 stream "Tell me a story"', "Stream a story in real-time")
|
|
451
|
+
.example('$0 stream "What time is it?"', "Stream with natural tool integration (default)")
|
|
452
|
+
.example('$0 stream "Tell me a story" --disable-tools', "Stream without tool integration"), async (argv) => {
|
|
441
453
|
// Default mode: Simple streaming message
|
|
442
454
|
// Debug mode: More detailed information
|
|
443
455
|
if (!argv.quiet && !argv.debug) {
|
|
@@ -447,13 +459,52 @@ const cli = yargs(args)
|
|
|
447
459
|
console.log(chalk.blue(`🔄 Streaming from ${argv.provider} provider with debug logging...\n`));
|
|
448
460
|
}
|
|
449
461
|
try {
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
: argv.
|
|
455
|
-
|
|
456
|
-
|
|
462
|
+
let stream;
|
|
463
|
+
if (argv.disableTools === true) {
|
|
464
|
+
// Tools disabled - use standard SDK
|
|
465
|
+
stream = await sdk.generateTextStream({
|
|
466
|
+
prompt: argv.prompt,
|
|
467
|
+
provider: argv.provider === "auto"
|
|
468
|
+
? undefined
|
|
469
|
+
: argv.provider,
|
|
470
|
+
temperature: argv.temperature,
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
// Tools enabled - use AgentEnhancedProvider for streaming tool calls
|
|
475
|
+
// Map provider to supported AgentEnhancedProvider types
|
|
476
|
+
const supportedProvider = (() => {
|
|
477
|
+
switch (argv.provider) {
|
|
478
|
+
case "openai":
|
|
479
|
+
case "anthropic":
|
|
480
|
+
case "google-ai":
|
|
481
|
+
return argv.provider;
|
|
482
|
+
case "auto":
|
|
483
|
+
default:
|
|
484
|
+
return "google-ai"; // Default to google-ai for best tool support
|
|
485
|
+
}
|
|
486
|
+
})();
|
|
487
|
+
const agentProvider = new AgentEnhancedProvider({
|
|
488
|
+
provider: supportedProvider,
|
|
489
|
+
model: undefined, // Use default model for provider
|
|
490
|
+
toolCategory: "all", // Enable all tool categories
|
|
491
|
+
});
|
|
492
|
+
// Note: AgentEnhancedProvider doesn't support streaming with tools yet
|
|
493
|
+
// Fall back to generateText for now
|
|
494
|
+
const result = await agentProvider.generateText(argv.prompt);
|
|
495
|
+
// Simulate streaming by outputting the result
|
|
496
|
+
const text = result?.text || "";
|
|
497
|
+
const CHUNK_SIZE = 10;
|
|
498
|
+
const DELAY_MS = 50;
|
|
499
|
+
for (let i = 0; i < text.length; i += CHUNK_SIZE) {
|
|
500
|
+
process.stdout.write(text.slice(i, i + CHUNK_SIZE));
|
|
501
|
+
await new Promise(resolve => setTimeout(resolve, DELAY_MS)); // Small delay
|
|
502
|
+
}
|
|
503
|
+
if (!argv.quiet) {
|
|
504
|
+
process.stdout.write("\n");
|
|
505
|
+
}
|
|
506
|
+
return; // Exit early for agent mode
|
|
507
|
+
}
|
|
457
508
|
for await (const chunk of stream) {
|
|
458
509
|
process.stdout.write(chunk.content);
|
|
459
510
|
// In debug mode, interleaved logging would appear here
|
|
@@ -13,16 +13,36 @@ interface AgentConfig {
|
|
|
13
13
|
toolCategory?: "basic" | "filesystem" | "utility" | "all";
|
|
14
14
|
maxSteps?: number;
|
|
15
15
|
enableTools?: boolean;
|
|
16
|
+
enableMCP?: boolean;
|
|
17
|
+
mcpInitTimeoutMs?: number;
|
|
18
|
+
mcpDiscoveryOptions?: {
|
|
19
|
+
searchPaths?: string[];
|
|
20
|
+
configFiles?: string[];
|
|
21
|
+
autoDiscover?: boolean;
|
|
22
|
+
};
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
25
|
* Agent-Enhanced Provider Class
|
|
19
26
|
* Provides AI generation with tool calling capabilities
|
|
27
|
+
* Now includes MCP tool integration alongside direct tools
|
|
20
28
|
*/
|
|
21
29
|
export declare class AgentEnhancedProvider implements AIProvider {
|
|
22
30
|
private config;
|
|
23
31
|
private model;
|
|
32
|
+
private mcpSystem;
|
|
33
|
+
private mcpInitialized;
|
|
34
|
+
private mcpInitializing;
|
|
35
|
+
private mcpInitFailed;
|
|
24
36
|
constructor(config: AgentConfig);
|
|
25
37
|
private createModel;
|
|
38
|
+
/**
|
|
39
|
+
* Initialize MCP registry with auto-discovery
|
|
40
|
+
*/
|
|
41
|
+
private initializeMCP;
|
|
42
|
+
/**
|
|
43
|
+
* Get combined tools: direct tools + MCP tools
|
|
44
|
+
*/
|
|
45
|
+
private getCombinedTools;
|
|
26
46
|
generateText(optionsOrPrompt: TextGenerationOptions | string): Promise<GenerateTextResult<ToolSet, unknown> | null>;
|
|
27
47
|
streamText(optionsOrPrompt: StreamTextOptions | string): Promise<StreamTextResult<ToolSet, unknown> | null>;
|
|
28
48
|
/**
|
|
@@ -7,22 +7,39 @@ import { google } from "@ai-sdk/google";
|
|
|
7
7
|
import { openai } from "@ai-sdk/openai";
|
|
8
8
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
9
9
|
import { getToolsForCategory, } from "../agent/direct-tools.js";
|
|
10
|
+
import { UnifiedMCPSystem } from "../mcp/unified-mcp.js";
|
|
11
|
+
import { mcpLogger } from "../mcp/logging.js";
|
|
10
12
|
/**
|
|
11
13
|
* Agent-Enhanced Provider Class
|
|
12
14
|
* Provides AI generation with tool calling capabilities
|
|
15
|
+
* Now includes MCP tool integration alongside direct tools
|
|
13
16
|
*/
|
|
14
17
|
export class AgentEnhancedProvider {
|
|
15
18
|
config;
|
|
16
19
|
model;
|
|
20
|
+
mcpSystem = null;
|
|
21
|
+
mcpInitialized = false;
|
|
22
|
+
mcpInitializing = false;
|
|
23
|
+
mcpInitFailed = false;
|
|
17
24
|
constructor(config) {
|
|
18
25
|
this.config = {
|
|
19
26
|
maxSteps: 5,
|
|
20
27
|
toolCategory: "all",
|
|
21
28
|
enableTools: true,
|
|
29
|
+
enableMCP: true,
|
|
30
|
+
mcpDiscoveryOptions: {
|
|
31
|
+
autoDiscover: true,
|
|
32
|
+
searchPaths: [process.cwd()],
|
|
33
|
+
configFiles: [".mcp-config.json", ".mcp-servers.json"],
|
|
34
|
+
},
|
|
22
35
|
...config,
|
|
23
36
|
};
|
|
24
37
|
// Initialize the AI model based on provider
|
|
25
38
|
this.model = this.createModel();
|
|
39
|
+
// Initialize MCP registry if enabled
|
|
40
|
+
if (this.config.enableMCP) {
|
|
41
|
+
this.initializeMCP();
|
|
42
|
+
}
|
|
26
43
|
}
|
|
27
44
|
createModel() {
|
|
28
45
|
const { provider, model } = this.config;
|
|
@@ -37,28 +54,248 @@ export class AgentEnhancedProvider {
|
|
|
37
54
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
38
55
|
}
|
|
39
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize MCP registry with auto-discovery
|
|
59
|
+
*/
|
|
60
|
+
async initializeMCP() {
|
|
61
|
+
if (this.mcpInitializing || this.mcpInitFailed) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.mcpInitializing = true;
|
|
65
|
+
try {
|
|
66
|
+
mcpLogger.info("[AgentEnhancedProvider] Initializing MCP integration...");
|
|
67
|
+
this.mcpSystem = new UnifiedMCPSystem({
|
|
68
|
+
configPath: this.config.mcpDiscoveryOptions?.configFiles?.[0] || ".mcp-config.json",
|
|
69
|
+
enableExternalServers: true,
|
|
70
|
+
enableInternalServers: true,
|
|
71
|
+
autoInitialize: false
|
|
72
|
+
});
|
|
73
|
+
// ADD TIMEOUT to prevent hanging forever
|
|
74
|
+
const initPromise = this.mcpSystem.initialize();
|
|
75
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('MCP initialization timeout after 15 seconds')), this.config.mcpInitTimeoutMs || 15000));
|
|
76
|
+
await Promise.race([initPromise, timeoutPromise]);
|
|
77
|
+
this.mcpInitialized = true;
|
|
78
|
+
mcpLogger.info("[AgentEnhancedProvider] MCP integration initialized successfully");
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
mcpLogger.error("[AgentEnhancedProvider] Failed to initialize MCP:", error);
|
|
82
|
+
this.mcpSystem = null;
|
|
83
|
+
this.mcpInitialized = false;
|
|
84
|
+
this.mcpInitFailed = true;
|
|
85
|
+
// Don't throw - continue with direct tools only
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
this.mcpInitializing = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get combined tools: direct tools + MCP tools
|
|
93
|
+
*/
|
|
94
|
+
async getCombinedTools() {
|
|
95
|
+
const directTools = this.config.enableTools
|
|
96
|
+
? getToolsForCategory(this.config.toolCategory)
|
|
97
|
+
: {};
|
|
98
|
+
// If MCP is disabled or failed to initialize, return only direct tools
|
|
99
|
+
if (!this.config.enableMCP || !this.mcpSystem) {
|
|
100
|
+
return directTools;
|
|
101
|
+
}
|
|
102
|
+
// Get MCP tools if available
|
|
103
|
+
let mcpTools = {};
|
|
104
|
+
try {
|
|
105
|
+
// Skip if MCP failed to initialize or is still initializing
|
|
106
|
+
if (this.mcpInitFailed || this.mcpInitializing || !this.mcpInitialized || !this.mcpSystem) {
|
|
107
|
+
return directTools;
|
|
108
|
+
}
|
|
109
|
+
const mcpToolInfos = await this.mcpSystem.listTools();
|
|
110
|
+
// Convert MCP tools to AI SDK format
|
|
111
|
+
for (const toolInfo of mcpToolInfos) {
|
|
112
|
+
const toolKey = `mcp_${toolInfo.name}`;
|
|
113
|
+
mcpTools[toolKey] = {
|
|
114
|
+
description: toolInfo.description || `MCP tool: ${toolInfo.name}`,
|
|
115
|
+
parameters: toolInfo.inputSchema || {},
|
|
116
|
+
execute: async (args) => {
|
|
117
|
+
try {
|
|
118
|
+
const context = {
|
|
119
|
+
sessionId: 'cli-session',
|
|
120
|
+
userId: 'cli-user',
|
|
121
|
+
secureFS: {
|
|
122
|
+
readFile: async (path, encoding) => {
|
|
123
|
+
const fs = await import('fs/promises');
|
|
124
|
+
return encoding ? fs.readFile(path, { encoding: encoding }) : fs.readFile(path);
|
|
125
|
+
},
|
|
126
|
+
writeFile: async (path, content) => {
|
|
127
|
+
const fs = await import('fs/promises');
|
|
128
|
+
await fs.writeFile(path, content);
|
|
129
|
+
},
|
|
130
|
+
readdir: async (path) => {
|
|
131
|
+
const fs = await import('fs/promises');
|
|
132
|
+
return fs.readdir(path);
|
|
133
|
+
},
|
|
134
|
+
stat: async (path) => {
|
|
135
|
+
const fs = await import('fs/promises');
|
|
136
|
+
return fs.stat(path);
|
|
137
|
+
},
|
|
138
|
+
mkdir: async (path, options) => {
|
|
139
|
+
const fs = await import('fs/promises');
|
|
140
|
+
await fs.mkdir(path, options);
|
|
141
|
+
},
|
|
142
|
+
exists: async (path) => {
|
|
143
|
+
const fs = await import('fs/promises');
|
|
144
|
+
try {
|
|
145
|
+
await fs.access(path);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
path: {
|
|
154
|
+
join: (...paths) => {
|
|
155
|
+
const path = require('path');
|
|
156
|
+
return path.join(...paths);
|
|
157
|
+
},
|
|
158
|
+
resolve: (...paths) => {
|
|
159
|
+
const path = require('path');
|
|
160
|
+
return path.resolve(...paths);
|
|
161
|
+
},
|
|
162
|
+
relative: (from, to) => {
|
|
163
|
+
const path = require('path');
|
|
164
|
+
return path.relative(from, to);
|
|
165
|
+
},
|
|
166
|
+
dirname: (path) => {
|
|
167
|
+
const pathLib = require('path');
|
|
168
|
+
return pathLib.dirname(path);
|
|
169
|
+
},
|
|
170
|
+
basename: (path, ext) => {
|
|
171
|
+
const pathLib = require('path');
|
|
172
|
+
return pathLib.basename(path, ext);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
grantedPermissions: ['read', 'write', 'execute'],
|
|
176
|
+
log: (level, message, data) => {
|
|
177
|
+
const logFn = mcpLogger[level];
|
|
178
|
+
if (typeof logFn === 'function') {
|
|
179
|
+
if (data) {
|
|
180
|
+
logFn(`${message} ${JSON.stringify(data)}`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
logFn(message);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const result = await this.mcpSystem.executeTool(toolInfo.name, args, context);
|
|
189
|
+
return result.data || result;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
mcpLogger.error(`MCP tool ${toolInfo.name} execution failed:`, error);
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
mcpLogger.info(`[AgentEnhancedProvider] Loaded ${Object.keys(mcpTools).length} MCP tools`);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
mcpLogger.error("[AgentEnhancedProvider] Failed to load MCP tools:", error);
|
|
202
|
+
}
|
|
203
|
+
return { ...directTools, ...mcpTools };
|
|
204
|
+
}
|
|
40
205
|
async generateText(optionsOrPrompt) {
|
|
41
206
|
const options = typeof optionsOrPrompt === "string"
|
|
42
207
|
? { prompt: optionsOrPrompt }
|
|
43
208
|
: optionsOrPrompt;
|
|
44
209
|
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt, schema, } = options;
|
|
45
|
-
// Get tools if enabled
|
|
210
|
+
// Get combined tools (direct + MCP) if enabled
|
|
46
211
|
const tools = this.config.enableTools
|
|
47
|
-
?
|
|
212
|
+
? await this.getCombinedTools()
|
|
48
213
|
: {};
|
|
214
|
+
const log = (msg, data) => {
|
|
215
|
+
mcpLogger.info(`[AgentEnhancedProvider] ${msg}`, data ? JSON.stringify(data, null, 2) : '');
|
|
216
|
+
};
|
|
217
|
+
log('Starting text generation', {
|
|
218
|
+
prompt: prompt.substring(0, 100),
|
|
219
|
+
toolsCount: Object.keys(tools).length,
|
|
220
|
+
maxSteps: this.config.maxSteps
|
|
221
|
+
});
|
|
49
222
|
try {
|
|
223
|
+
// The AI SDK with maxSteps automatically handles tool calling and result integration
|
|
50
224
|
const result = await generateText({
|
|
51
225
|
model: this.model,
|
|
52
226
|
prompt: systemPrompt
|
|
53
227
|
? `System: ${systemPrompt}\n\nUser: ${prompt}`
|
|
54
228
|
: prompt,
|
|
55
229
|
tools,
|
|
56
|
-
maxSteps: this.config.maxSteps,
|
|
230
|
+
maxSteps: this.config.maxSteps, // This enables automatic tool calling
|
|
57
231
|
temperature,
|
|
58
232
|
maxTokens,
|
|
59
|
-
// Force tool usage for specific patterns
|
|
60
233
|
toolChoice: this.shouldForceToolUsage(prompt) ? "required" : "auto",
|
|
61
234
|
});
|
|
235
|
+
log('Generation completed', {
|
|
236
|
+
text: result.text?.substring(0, 200),
|
|
237
|
+
finishReason: result.finishReason,
|
|
238
|
+
toolCallsCount: result.toolCalls?.length || 0,
|
|
239
|
+
toolResultsCount: result.toolResults?.length || 0,
|
|
240
|
+
stepsCount: result.steps?.length || 0
|
|
241
|
+
});
|
|
242
|
+
// Check if tools were called but no final text was generated
|
|
243
|
+
if (result.finishReason === 'tool-calls' && !result.text && result.toolResults?.length > 0) {
|
|
244
|
+
log('Tools called but no final text generated, creating summary response');
|
|
245
|
+
try {
|
|
246
|
+
// Extract tool results and create a summary prompt
|
|
247
|
+
let toolResultsSummary = '';
|
|
248
|
+
if (result.toolResults) {
|
|
249
|
+
for (const toolResult of result.toolResults) {
|
|
250
|
+
const resultData = toolResult.result || toolResult;
|
|
251
|
+
// Try to extract meaningful data from the result
|
|
252
|
+
if (typeof resultData === 'object' && resultData !== null) {
|
|
253
|
+
if (resultData.success && resultData.items) {
|
|
254
|
+
// This looks like a filesystem listing
|
|
255
|
+
toolResultsSummary += `Directory listing for ${resultData.path}:\n`;
|
|
256
|
+
for (const item of resultData.items) {
|
|
257
|
+
toolResultsSummary += `- ${item.name} (${item.type})\n`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
toolResultsSummary += JSON.stringify(resultData, null, 2);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
toolResultsSummary += String(resultData);
|
|
266
|
+
}
|
|
267
|
+
toolResultsSummary += '\n\n';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
log('Tool results extracted', {
|
|
271
|
+
summaryLength: toolResultsSummary.length,
|
|
272
|
+
preview: toolResultsSummary.substring(0, 200)
|
|
273
|
+
});
|
|
274
|
+
// Create a simple, direct summary
|
|
275
|
+
const finalText = `Based on the user request "${prompt}", here's what I found:\n\n${toolResultsSummary}`;
|
|
276
|
+
log('Final text created', {
|
|
277
|
+
textLength: finalText.length,
|
|
278
|
+
preview: finalText.substring(0, 200)
|
|
279
|
+
});
|
|
280
|
+
// Return result with the formatted text
|
|
281
|
+
return {
|
|
282
|
+
...result,
|
|
283
|
+
text: finalText,
|
|
284
|
+
finishReason: 'stop'
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
log('Error in summary generation', { error: error instanceof Error ? error.message : String(error) });
|
|
289
|
+
// Fallback: return raw tool results
|
|
290
|
+
const fallbackText = `Tool execution completed. Raw results: ${JSON.stringify(result.toolResults, null, 2)}`;
|
|
291
|
+
return {
|
|
292
|
+
...result,
|
|
293
|
+
text: fallbackText,
|
|
294
|
+
finishReason: 'stop'
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Return the full result - the AI SDK has already handled tool execution and integration
|
|
62
299
|
return result;
|
|
63
300
|
}
|
|
64
301
|
catch (error) {
|
|
@@ -71,9 +308,9 @@ export class AgentEnhancedProvider {
|
|
|
71
308
|
? { prompt: optionsOrPrompt }
|
|
72
309
|
: optionsOrPrompt;
|
|
73
310
|
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt, } = options;
|
|
74
|
-
// Get tools if enabled
|
|
311
|
+
// Get combined tools (direct + MCP) if enabled
|
|
75
312
|
const tools = this.config.enableTools
|
|
76
|
-
?
|
|
313
|
+
? await this.getCombinedTools()
|
|
77
314
|
: {};
|
|
78
315
|
try {
|
|
79
316
|
const result = await streamText({
|
|
@@ -4,7 +4,8 @@ import { logger } from "../utils/logger.js";
|
|
|
4
4
|
// CRITICAL: Setup environment variables early for AI SDK compatibility
|
|
5
5
|
// The AI SDK specifically looks for GOOGLE_GENERATIVE_AI_API_KEY
|
|
6
6
|
// We need to ensure this is set before any AI SDK operations
|
|
7
|
-
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
7
|
+
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
8
|
+
process.env.GOOGLE_AI_API_KEY) {
|
|
8
9
|
process.env.GOOGLE_GENERATIVE_AI_API_KEY = process.env.GOOGLE_AI_API_KEY;
|
|
9
10
|
}
|
|
10
11
|
// Default system context
|
|
@@ -20,7 +21,8 @@ const getGoogleAIApiKey = () => {
|
|
|
20
21
|
}
|
|
21
22
|
// Ensure GOOGLE_GENERATIVE_AI_API_KEY is set for @ai-sdk/google compatibility
|
|
22
23
|
// The AI SDK specifically looks for this variable name
|
|
23
|
-
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
24
|
+
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
25
|
+
process.env.GOOGLE_AI_API_KEY) {
|
|
24
26
|
process.env.GOOGLE_GENERATIVE_AI_API_KEY = process.env.GOOGLE_AI_API_KEY;
|
|
25
27
|
}
|
|
26
28
|
return apiKey;
|
|
@@ -13,16 +13,36 @@ interface AgentConfig {
|
|
|
13
13
|
toolCategory?: "basic" | "filesystem" | "utility" | "all";
|
|
14
14
|
maxSteps?: number;
|
|
15
15
|
enableTools?: boolean;
|
|
16
|
+
enableMCP?: boolean;
|
|
17
|
+
mcpInitTimeoutMs?: number;
|
|
18
|
+
mcpDiscoveryOptions?: {
|
|
19
|
+
searchPaths?: string[];
|
|
20
|
+
configFiles?: string[];
|
|
21
|
+
autoDiscover?: boolean;
|
|
22
|
+
};
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
25
|
* Agent-Enhanced Provider Class
|
|
19
26
|
* Provides AI generation with tool calling capabilities
|
|
27
|
+
* Now includes MCP tool integration alongside direct tools
|
|
20
28
|
*/
|
|
21
29
|
export declare class AgentEnhancedProvider implements AIProvider {
|
|
22
30
|
private config;
|
|
23
31
|
private model;
|
|
32
|
+
private mcpSystem;
|
|
33
|
+
private mcpInitialized;
|
|
34
|
+
private mcpInitializing;
|
|
35
|
+
private mcpInitFailed;
|
|
24
36
|
constructor(config: AgentConfig);
|
|
25
37
|
private createModel;
|
|
38
|
+
/**
|
|
39
|
+
* Initialize MCP registry with auto-discovery
|
|
40
|
+
*/
|
|
41
|
+
private initializeMCP;
|
|
42
|
+
/**
|
|
43
|
+
* Get combined tools: direct tools + MCP tools
|
|
44
|
+
*/
|
|
45
|
+
private getCombinedTools;
|
|
26
46
|
generateText(optionsOrPrompt: TextGenerationOptions | string): Promise<GenerateTextResult<ToolSet, unknown> | null>;
|
|
27
47
|
streamText(optionsOrPrompt: StreamTextOptions | string): Promise<StreamTextResult<ToolSet, unknown> | null>;
|
|
28
48
|
/**
|
|
@@ -2,27 +2,44 @@
|
|
|
2
2
|
* Agent-Enhanced Provider for NeuroLink CLI
|
|
3
3
|
* Integrates direct tools with AI providers for true agent functionality
|
|
4
4
|
*/
|
|
5
|
-
import { generateText, streamText, } from "ai";
|
|
5
|
+
import { generateText, streamText, tool, } from "ai";
|
|
6
6
|
import { google } from "@ai-sdk/google";
|
|
7
7
|
import { openai } from "@ai-sdk/openai";
|
|
8
8
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
9
9
|
import { directAgentTools, getToolsForCategory, } from "../agent/direct-tools.js";
|
|
10
|
+
import { UnifiedMCPSystem } from "../mcp/unified-mcp.js";
|
|
11
|
+
import { mcpLogger } from "../mcp/logging.js";
|
|
10
12
|
/**
|
|
11
13
|
* Agent-Enhanced Provider Class
|
|
12
14
|
* Provides AI generation with tool calling capabilities
|
|
15
|
+
* Now includes MCP tool integration alongside direct tools
|
|
13
16
|
*/
|
|
14
17
|
export class AgentEnhancedProvider {
|
|
15
18
|
config;
|
|
16
19
|
model;
|
|
20
|
+
mcpSystem = null;
|
|
21
|
+
mcpInitialized = false;
|
|
22
|
+
mcpInitializing = false;
|
|
23
|
+
mcpInitFailed = false;
|
|
17
24
|
constructor(config) {
|
|
18
25
|
this.config = {
|
|
19
26
|
maxSteps: 5,
|
|
20
27
|
toolCategory: "all",
|
|
21
28
|
enableTools: true,
|
|
29
|
+
enableMCP: true,
|
|
30
|
+
mcpDiscoveryOptions: {
|
|
31
|
+
autoDiscover: true,
|
|
32
|
+
searchPaths: [process.cwd()],
|
|
33
|
+
configFiles: [".mcp-config.json", ".mcp-servers.json"],
|
|
34
|
+
},
|
|
22
35
|
...config,
|
|
23
36
|
};
|
|
24
37
|
// Initialize the AI model based on provider
|
|
25
38
|
this.model = this.createModel();
|
|
39
|
+
// Initialize MCP registry if enabled
|
|
40
|
+
if (this.config.enableMCP) {
|
|
41
|
+
this.initializeMCP();
|
|
42
|
+
}
|
|
26
43
|
}
|
|
27
44
|
createModel() {
|
|
28
45
|
const { provider, model } = this.config;
|
|
@@ -37,28 +54,248 @@ export class AgentEnhancedProvider {
|
|
|
37
54
|
throw new Error(`Unsupported provider: ${provider}`);
|
|
38
55
|
}
|
|
39
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize MCP registry with auto-discovery
|
|
59
|
+
*/
|
|
60
|
+
async initializeMCP() {
|
|
61
|
+
if (this.mcpInitializing || this.mcpInitFailed) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
this.mcpInitializing = true;
|
|
65
|
+
try {
|
|
66
|
+
mcpLogger.info("[AgentEnhancedProvider] Initializing MCP integration...");
|
|
67
|
+
this.mcpSystem = new UnifiedMCPSystem({
|
|
68
|
+
configPath: this.config.mcpDiscoveryOptions?.configFiles?.[0] || ".mcp-config.json",
|
|
69
|
+
enableExternalServers: true,
|
|
70
|
+
enableInternalServers: true,
|
|
71
|
+
autoInitialize: false
|
|
72
|
+
});
|
|
73
|
+
// ADD TIMEOUT to prevent hanging forever
|
|
74
|
+
const initPromise = this.mcpSystem.initialize();
|
|
75
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('MCP initialization timeout after 15 seconds')), this.config.mcpInitTimeoutMs || 15000));
|
|
76
|
+
await Promise.race([initPromise, timeoutPromise]);
|
|
77
|
+
this.mcpInitialized = true;
|
|
78
|
+
mcpLogger.info("[AgentEnhancedProvider] MCP integration initialized successfully");
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
mcpLogger.error("[AgentEnhancedProvider] Failed to initialize MCP:", error);
|
|
82
|
+
this.mcpSystem = null;
|
|
83
|
+
this.mcpInitialized = false;
|
|
84
|
+
this.mcpInitFailed = true;
|
|
85
|
+
// Don't throw - continue with direct tools only
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
this.mcpInitializing = false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get combined tools: direct tools + MCP tools
|
|
93
|
+
*/
|
|
94
|
+
async getCombinedTools() {
|
|
95
|
+
const directTools = this.config.enableTools
|
|
96
|
+
? getToolsForCategory(this.config.toolCategory)
|
|
97
|
+
: {};
|
|
98
|
+
// If MCP is disabled or failed to initialize, return only direct tools
|
|
99
|
+
if (!this.config.enableMCP || !this.mcpSystem) {
|
|
100
|
+
return directTools;
|
|
101
|
+
}
|
|
102
|
+
// Get MCP tools if available
|
|
103
|
+
let mcpTools = {};
|
|
104
|
+
try {
|
|
105
|
+
// Skip if MCP failed to initialize or is still initializing
|
|
106
|
+
if (this.mcpInitFailed || this.mcpInitializing || !this.mcpInitialized || !this.mcpSystem) {
|
|
107
|
+
return directTools;
|
|
108
|
+
}
|
|
109
|
+
const mcpToolInfos = await this.mcpSystem.listTools();
|
|
110
|
+
// Convert MCP tools to AI SDK format
|
|
111
|
+
for (const toolInfo of mcpToolInfos) {
|
|
112
|
+
const toolKey = `mcp_${toolInfo.name}`;
|
|
113
|
+
mcpTools[toolKey] = {
|
|
114
|
+
description: toolInfo.description || `MCP tool: ${toolInfo.name}`,
|
|
115
|
+
parameters: toolInfo.inputSchema || {},
|
|
116
|
+
execute: async (args) => {
|
|
117
|
+
try {
|
|
118
|
+
const context = {
|
|
119
|
+
sessionId: 'cli-session',
|
|
120
|
+
userId: 'cli-user',
|
|
121
|
+
secureFS: {
|
|
122
|
+
readFile: async (path, encoding) => {
|
|
123
|
+
const fs = await import('fs/promises');
|
|
124
|
+
return encoding ? fs.readFile(path, { encoding: encoding }) : fs.readFile(path);
|
|
125
|
+
},
|
|
126
|
+
writeFile: async (path, content) => {
|
|
127
|
+
const fs = await import('fs/promises');
|
|
128
|
+
await fs.writeFile(path, content);
|
|
129
|
+
},
|
|
130
|
+
readdir: async (path) => {
|
|
131
|
+
const fs = await import('fs/promises');
|
|
132
|
+
return fs.readdir(path);
|
|
133
|
+
},
|
|
134
|
+
stat: async (path) => {
|
|
135
|
+
const fs = await import('fs/promises');
|
|
136
|
+
return fs.stat(path);
|
|
137
|
+
},
|
|
138
|
+
mkdir: async (path, options) => {
|
|
139
|
+
const fs = await import('fs/promises');
|
|
140
|
+
await fs.mkdir(path, options);
|
|
141
|
+
},
|
|
142
|
+
exists: async (path) => {
|
|
143
|
+
const fs = await import('fs/promises');
|
|
144
|
+
try {
|
|
145
|
+
await fs.access(path);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
path: {
|
|
154
|
+
join: (...paths) => {
|
|
155
|
+
const path = require('path');
|
|
156
|
+
return path.join(...paths);
|
|
157
|
+
},
|
|
158
|
+
resolve: (...paths) => {
|
|
159
|
+
const path = require('path');
|
|
160
|
+
return path.resolve(...paths);
|
|
161
|
+
},
|
|
162
|
+
relative: (from, to) => {
|
|
163
|
+
const path = require('path');
|
|
164
|
+
return path.relative(from, to);
|
|
165
|
+
},
|
|
166
|
+
dirname: (path) => {
|
|
167
|
+
const pathLib = require('path');
|
|
168
|
+
return pathLib.dirname(path);
|
|
169
|
+
},
|
|
170
|
+
basename: (path, ext) => {
|
|
171
|
+
const pathLib = require('path');
|
|
172
|
+
return pathLib.basename(path, ext);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
grantedPermissions: ['read', 'write', 'execute'],
|
|
176
|
+
log: (level, message, data) => {
|
|
177
|
+
const logFn = mcpLogger[level];
|
|
178
|
+
if (typeof logFn === 'function') {
|
|
179
|
+
if (data) {
|
|
180
|
+
logFn(`${message} ${JSON.stringify(data)}`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
logFn(message);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
const result = await this.mcpSystem.executeTool(toolInfo.name, args, context);
|
|
189
|
+
return result.data || result;
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
mcpLogger.error(`MCP tool ${toolInfo.name} execution failed:`, error);
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
mcpLogger.info(`[AgentEnhancedProvider] Loaded ${Object.keys(mcpTools).length} MCP tools`);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
mcpLogger.error("[AgentEnhancedProvider] Failed to load MCP tools:", error);
|
|
202
|
+
}
|
|
203
|
+
return { ...directTools, ...mcpTools };
|
|
204
|
+
}
|
|
40
205
|
async generateText(optionsOrPrompt) {
|
|
41
206
|
const options = typeof optionsOrPrompt === "string"
|
|
42
207
|
? { prompt: optionsOrPrompt }
|
|
43
208
|
: optionsOrPrompt;
|
|
44
209
|
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt, schema, } = options;
|
|
45
|
-
// Get tools if enabled
|
|
210
|
+
// Get combined tools (direct + MCP) if enabled
|
|
46
211
|
const tools = this.config.enableTools
|
|
47
|
-
?
|
|
212
|
+
? await this.getCombinedTools()
|
|
48
213
|
: {};
|
|
214
|
+
const log = (msg, data) => {
|
|
215
|
+
mcpLogger.info(`[AgentEnhancedProvider] ${msg}`, data ? JSON.stringify(data, null, 2) : '');
|
|
216
|
+
};
|
|
217
|
+
log('Starting text generation', {
|
|
218
|
+
prompt: prompt.substring(0, 100),
|
|
219
|
+
toolsCount: Object.keys(tools).length,
|
|
220
|
+
maxSteps: this.config.maxSteps
|
|
221
|
+
});
|
|
49
222
|
try {
|
|
223
|
+
// The AI SDK with maxSteps automatically handles tool calling and result integration
|
|
50
224
|
const result = await generateText({
|
|
51
225
|
model: this.model,
|
|
52
226
|
prompt: systemPrompt
|
|
53
227
|
? `System: ${systemPrompt}\n\nUser: ${prompt}`
|
|
54
228
|
: prompt,
|
|
55
229
|
tools,
|
|
56
|
-
maxSteps: this.config.maxSteps,
|
|
230
|
+
maxSteps: this.config.maxSteps, // This enables automatic tool calling
|
|
57
231
|
temperature,
|
|
58
232
|
maxTokens,
|
|
59
|
-
// Force tool usage for specific patterns
|
|
60
233
|
toolChoice: this.shouldForceToolUsage(prompt) ? "required" : "auto",
|
|
61
234
|
});
|
|
235
|
+
log('Generation completed', {
|
|
236
|
+
text: result.text?.substring(0, 200),
|
|
237
|
+
finishReason: result.finishReason,
|
|
238
|
+
toolCallsCount: result.toolCalls?.length || 0,
|
|
239
|
+
toolResultsCount: result.toolResults?.length || 0,
|
|
240
|
+
stepsCount: result.steps?.length || 0
|
|
241
|
+
});
|
|
242
|
+
// Check if tools were called but no final text was generated
|
|
243
|
+
if (result.finishReason === 'tool-calls' && !result.text && result.toolResults?.length > 0) {
|
|
244
|
+
log('Tools called but no final text generated, creating summary response');
|
|
245
|
+
try {
|
|
246
|
+
// Extract tool results and create a summary prompt
|
|
247
|
+
let toolResultsSummary = '';
|
|
248
|
+
if (result.toolResults) {
|
|
249
|
+
for (const toolResult of result.toolResults) {
|
|
250
|
+
const resultData = toolResult.result || toolResult;
|
|
251
|
+
// Try to extract meaningful data from the result
|
|
252
|
+
if (typeof resultData === 'object' && resultData !== null) {
|
|
253
|
+
if (resultData.success && resultData.items) {
|
|
254
|
+
// This looks like a filesystem listing
|
|
255
|
+
toolResultsSummary += `Directory listing for ${resultData.path}:\n`;
|
|
256
|
+
for (const item of resultData.items) {
|
|
257
|
+
toolResultsSummary += `- ${item.name} (${item.type})\n`;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
toolResultsSummary += JSON.stringify(resultData, null, 2);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else {
|
|
265
|
+
toolResultsSummary += String(resultData);
|
|
266
|
+
}
|
|
267
|
+
toolResultsSummary += '\n\n';
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
log('Tool results extracted', {
|
|
271
|
+
summaryLength: toolResultsSummary.length,
|
|
272
|
+
preview: toolResultsSummary.substring(0, 200)
|
|
273
|
+
});
|
|
274
|
+
// Create a simple, direct summary
|
|
275
|
+
const finalText = `Based on the user request "${prompt}", here's what I found:\n\n${toolResultsSummary}`;
|
|
276
|
+
log('Final text created', {
|
|
277
|
+
textLength: finalText.length,
|
|
278
|
+
preview: finalText.substring(0, 200)
|
|
279
|
+
});
|
|
280
|
+
// Return result with the formatted text
|
|
281
|
+
return {
|
|
282
|
+
...result,
|
|
283
|
+
text: finalText,
|
|
284
|
+
finishReason: 'stop'
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
catch (error) {
|
|
288
|
+
log('Error in summary generation', { error: error instanceof Error ? error.message : String(error) });
|
|
289
|
+
// Fallback: return raw tool results
|
|
290
|
+
const fallbackText = `Tool execution completed. Raw results: ${JSON.stringify(result.toolResults, null, 2)}`;
|
|
291
|
+
return {
|
|
292
|
+
...result,
|
|
293
|
+
text: fallbackText,
|
|
294
|
+
finishReason: 'stop'
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Return the full result - the AI SDK has already handled tool execution and integration
|
|
62
299
|
return result;
|
|
63
300
|
}
|
|
64
301
|
catch (error) {
|
|
@@ -71,9 +308,9 @@ export class AgentEnhancedProvider {
|
|
|
71
308
|
? { prompt: optionsOrPrompt }
|
|
72
309
|
: optionsOrPrompt;
|
|
73
310
|
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt, } = options;
|
|
74
|
-
// Get tools if enabled
|
|
311
|
+
// Get combined tools (direct + MCP) if enabled
|
|
75
312
|
const tools = this.config.enableTools
|
|
76
|
-
?
|
|
313
|
+
? await this.getCombinedTools()
|
|
77
314
|
: {};
|
|
78
315
|
try {
|
|
79
316
|
const result = await streamText({
|
|
@@ -4,7 +4,8 @@ import { logger } from "../utils/logger.js";
|
|
|
4
4
|
// CRITICAL: Setup environment variables early for AI SDK compatibility
|
|
5
5
|
// The AI SDK specifically looks for GOOGLE_GENERATIVE_AI_API_KEY
|
|
6
6
|
// We need to ensure this is set before any AI SDK operations
|
|
7
|
-
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
7
|
+
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
8
|
+
process.env.GOOGLE_AI_API_KEY) {
|
|
8
9
|
process.env.GOOGLE_GENERATIVE_AI_API_KEY = process.env.GOOGLE_AI_API_KEY;
|
|
9
10
|
}
|
|
10
11
|
// Default system context
|
|
@@ -20,7 +21,8 @@ const getGoogleAIApiKey = () => {
|
|
|
20
21
|
}
|
|
21
22
|
// Ensure GOOGLE_GENERATIVE_AI_API_KEY is set for @ai-sdk/google compatibility
|
|
22
23
|
// The AI SDK specifically looks for this variable name
|
|
23
|
-
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
24
|
+
if (!process.env.GOOGLE_GENERATIVE_AI_API_KEY &&
|
|
25
|
+
process.env.GOOGLE_AI_API_KEY) {
|
|
24
26
|
process.env.GOOGLE_GENERATIVE_AI_API_KEY = process.env.GOOGLE_AI_API_KEY;
|
|
25
27
|
}
|
|
26
28
|
return apiKey;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Universal AI Development Platform with working MCP integration, multi-provider support, and professional CLI. Built-in tools operational, 58+ external MCP servers discoverable. Connect to filesystem, GitHub, database operations, and more. Build, test, and deploy AI applications with 9 major providers: OpenAI, Anthropic, Google AI, AWS Bedrock, Azure, Hugging Face, Ollama, and Mistral AI.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Juspay Technologies",
|
|
@@ -42,7 +42,52 @@
|
|
|
42
42
|
"lint": "prettier --check . && eslint .",
|
|
43
43
|
"format": "prettier --write .",
|
|
44
44
|
"changeset": "changeset",
|
|
45
|
-
"changeset:version": "changeset version && git add --all"
|
|
45
|
+
"changeset:version": "changeset version && git add --all",
|
|
46
|
+
"// ===== NEUROLINK DEVELOPER EXPERIENCE ENHANCEMENT 2.0 =====": "",
|
|
47
|
+
"// Environment & Setup (pnpm-first)": "",
|
|
48
|
+
"setup": "pnpm install && node tools/automation/environment-manager.js",
|
|
49
|
+
"setup:complete": "pnpm run setup && pnpm run project:organize && pnpm run env:validate",
|
|
50
|
+
"env:setup": "node tools/automation/environment-manager.js",
|
|
51
|
+
"env:validate": "node tools/automation/environment-manager.js --validate",
|
|
52
|
+
"env:backup": "node tools/automation/environment-manager.js --backup",
|
|
53
|
+
"env:list-backups": "node tools/automation/environment-manager.js --list-backups",
|
|
54
|
+
"// Project Management & Analysis": "",
|
|
55
|
+
"project:analyze": "node tools/automation/script-analyzer.js",
|
|
56
|
+
"project:cleanup": "node tools/automation/script-analyzer.js --execute",
|
|
57
|
+
"project:organize": "node tools/automation/project-organizer.js",
|
|
58
|
+
"project:health": "node tools/development/health-monitor.js",
|
|
59
|
+
"// Shell Script Conversion": "",
|
|
60
|
+
"convert:shell-scripts": "node tools/automation/shell-converter.js",
|
|
61
|
+
"convert:specific": "node tools/automation/shell-converter.js --specific",
|
|
62
|
+
"// Testing (Enhanced & Adaptive)": "",
|
|
63
|
+
"test:smart": "node tools/testing/adaptive-test-runner.js",
|
|
64
|
+
"test:providers": "node tools/testing/provider-validator.js",
|
|
65
|
+
"test:performance": "node tools/testing/performance-monitor.js",
|
|
66
|
+
"test:coverage": "vitest run --coverage",
|
|
67
|
+
"test:ci": "pnpm run test:smart && pnpm run test:coverage",
|
|
68
|
+
"// Content Generation (Cross-platform JS)": "",
|
|
69
|
+
"content:screenshots": "node tools/content/screenshot-automation.js",
|
|
70
|
+
"content:videos": "node tools/converted-scripts/generate-all-videos.js",
|
|
71
|
+
"content:cleanup": "node tools/converted-scripts/cleanup-hash-named-videos.js",
|
|
72
|
+
"content:all": "pnpm run content:screenshots && pnpm run content:videos",
|
|
73
|
+
"// Documentation Automation": "",
|
|
74
|
+
"docs:sync": "node tools/content/documentation-sync.js",
|
|
75
|
+
"docs:validate": "node tools/content/documentation-sync.js --validate",
|
|
76
|
+
"docs:generate": "pnpm run docs:sync && pnpm run content:screenshots",
|
|
77
|
+
"// Development & Monitoring": "",
|
|
78
|
+
"dev:full": "node tools/development/dev-server.js",
|
|
79
|
+
"dev:health": "node tools/development/health-monitor.js",
|
|
80
|
+
"dev:demo": "concurrently \"pnpm run dev\" \"node neurolink-demo/complete-enhanced-server.js\"",
|
|
81
|
+
"// Build & Deploy (Complete Pipeline)": "",
|
|
82
|
+
"build:complete": "node tools/automation/build-system.js",
|
|
83
|
+
"build:analyze": "node tools/development/dependency-analyzer.js",
|
|
84
|
+
"// Quality & Maintenance": "",
|
|
85
|
+
"quality:all": "pnpm run lint && pnpm run format && pnpm run test:ci",
|
|
86
|
+
"clean": "pnpm run content:cleanup && rm -rf dist .svelte-kit node_modules/.cache",
|
|
87
|
+
"reset": "pnpm run clean && pnpm install",
|
|
88
|
+
"audit": "pnpm audit && pnpm run build:analyze",
|
|
89
|
+
"// Release & Publishing": "",
|
|
90
|
+
"release": "pnpm run build:complete && pnpm run test:ci && changeset publish"
|
|
46
91
|
},
|
|
47
92
|
"files": [
|
|
48
93
|
"dist",
|