@juspay/neurolink 7.14.8 → 7.15.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 +6 -0
- package/README.md +58 -2
- package/dist/agent/directTools.d.ts +133 -0
- package/dist/agent/directTools.js +134 -0
- package/dist/lib/agent/directTools.d.ts +133 -0
- package/dist/lib/agent/directTools.js +134 -0
- package/dist/lib/mcp/servers/agent/directToolsServer.js +2 -0
- package/dist/lib/neurolink.js +15 -0
- package/dist/mcp/servers/agent/directToolsServer.js +2 -0
- package/dist/neurolink.js +15 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [7.15.0](https://github.com/juspay/neurolink/compare/v7.14.8...v7.15.0) (2025-08-19)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
- **(tools):** add websearch tool using Gemini AI for Google search integration BZ-43347 ([bcd5160](https://github.com/juspay/neurolink/commit/bcd516019db8a6b89ba6ecb39037b257fd955df0))
|
|
6
|
+
|
|
1
7
|
## [7.14.8](https://github.com/juspay/neurolink/compare/v7.14.7...v7.14.8) (2025-08-19)
|
|
2
8
|
|
|
3
9
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -284,6 +284,11 @@ echo 'OPENAI_API_KEY="sk-your-openai-key"' > .env
|
|
|
284
284
|
echo 'GOOGLE_AI_API_KEY="AIza-your-google-ai-key"' >> .env
|
|
285
285
|
echo 'AWS_ACCESS_KEY_ID="your-aws-access-key"' >> .env
|
|
286
286
|
|
|
287
|
+
# 🆕 NEW: Google Vertex AI for Websearch Tool
|
|
288
|
+
echo 'GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account.json"' >> .env
|
|
289
|
+
echo 'GOOGLE_VERTEX_PROJECT="your-gcp-project-id"' >> .env
|
|
290
|
+
echo 'GOOGLE_VERTEX_LOCATION="us-central1"' >> .env
|
|
291
|
+
|
|
287
292
|
# Test configuration
|
|
288
293
|
npx @juspay/neurolink status
|
|
289
294
|
```
|
|
@@ -337,12 +342,63 @@ console.log(productData.name, productData.price, productData.features);
|
|
|
337
342
|
|
|
338
343
|
**📖 [Complete Setup Guide](./docs/CONFIGURATION.md)** - All providers with detailed instructions
|
|
339
344
|
|
|
345
|
+
## 🔍 **NEW: Websearch Tool with Google Vertex AI Grounding**
|
|
346
|
+
|
|
347
|
+
**NeuroLink now includes a powerful websearch tool** that uses Google's native search grounding technology for real-time web information:
|
|
348
|
+
|
|
349
|
+
- **🔍 Native Google Search** - Uses Google's search grounding via Vertex AI
|
|
350
|
+
- **🎯 Real-time Results** - Access current web information during AI conversations
|
|
351
|
+
- **🔒 Credential Protection** - Only activates when Google Vertex AI credentials are properly configured
|
|
352
|
+
|
|
353
|
+
### Quick Setup & Test
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
# 1. Build the project first
|
|
357
|
+
pnpm run build
|
|
358
|
+
|
|
359
|
+
# 2. Set up environment variables (see detailed setup below)
|
|
360
|
+
cp .env.example .env
|
|
361
|
+
# Edit .env with your Google Vertex AI credentials
|
|
362
|
+
|
|
363
|
+
# 3. Test the websearch tool directly
|
|
364
|
+
node test-websearch-grounding.j
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Complete Google Vertex AI Setup
|
|
368
|
+
|
|
369
|
+
#### Configure Environment Variables
|
|
370
|
+
|
|
371
|
+
```bash
|
|
372
|
+
# Add to your .env file
|
|
373
|
+
GOOGLE_APPLICATION_CREDENTIALS="/absolute/path/to/neurolink-service-account.json"
|
|
374
|
+
GOOGLE_VERTEX_PROJECT="YOUR-PROJECT-ID"
|
|
375
|
+
GOOGLE_VERTEX_LOCATION="us-central1"
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
#### Step 3: Test the Setup
|
|
379
|
+
|
|
380
|
+
````bash
|
|
381
|
+
# Build the project first
|
|
382
|
+
pnpm run build
|
|
383
|
+
|
|
384
|
+
# Run the dedicated test script
|
|
385
|
+
node test-websearch-grounding.js
|
|
386
|
+
|
|
387
|
+
### Using the Websearch Tool
|
|
388
|
+
|
|
389
|
+
#### CLI Usage (Works with All Providers)
|
|
390
|
+
|
|
391
|
+
# With specific providers - websearch works across all providers
|
|
392
|
+
npx @juspay/neurolink generate "Weather in Tokyo now" --provider vertex
|
|
393
|
+
|
|
394
|
+
**Note:** The websearch tool gracefully handles missing credentials - it only activates when valid Google Vertex AI credentials are configured. Without proper credentials, other tools continue to work normally and AI responses fall back to training data.
|
|
395
|
+
|
|
340
396
|
## ✨ Key Features
|
|
341
397
|
|
|
342
398
|
- 🔗 **LiteLLM Integration** - **Access 100+ AI models** from all major providers through unified interface
|
|
343
399
|
- 🔍 **Smart Model Auto-Discovery** - OpenAI Compatible provider automatically detects available models via `/v1/models` endpoint
|
|
344
400
|
- 🏭 **Factory Pattern Architecture** - Unified provider management with BaseProvider inheritance
|
|
345
|
-
- 🔧 **Tools-First Design** - All providers automatically include
|
|
401
|
+
- 🔧 **Tools-First Design** - All providers automatically include 7 direct tools (getCurrentTime, readFile, listDirectory, calculateMath, writeFile, searchFiles, websearchGrounding)
|
|
346
402
|
- 🔄 **12 AI Providers** - OpenAI, Bedrock, Vertex AI, Google AI Studio, Anthropic, Azure, **LiteLLM**, **OpenAI Compatible**, Hugging Face, Ollama, Mistral AI, **SageMaker**
|
|
347
403
|
- 💰 **Cost Optimization** - Automatic selection of cheapest models and LiteLLM routing
|
|
348
404
|
- ⚡ **Automatic Fallback** - Never fail when providers are down, intelligent provider switching
|
|
@@ -398,7 +454,7 @@ const result = await neurolink.generate({
|
|
|
398
454
|
|
|
399
455
|
# Discover available MCP servers
|
|
400
456
|
npx @juspay/neurolink mcp discover --format table
|
|
401
|
-
|
|
457
|
+
````
|
|
402
458
|
|
|
403
459
|
### 🔧 SDK Custom Tool Registration (NEW!)
|
|
404
460
|
|
|
@@ -346,6 +346,139 @@ export declare const directAgentTools: {
|
|
|
346
346
|
count?: undefined;
|
|
347
347
|
}>;
|
|
348
348
|
};
|
|
349
|
+
websearchGrounding: import("ai").Tool<z.ZodObject<{
|
|
350
|
+
query: z.ZodString;
|
|
351
|
+
maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
352
|
+
maxWords: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
353
|
+
}, "strip", z.ZodTypeAny, {
|
|
354
|
+
query: string;
|
|
355
|
+
maxResults: number;
|
|
356
|
+
maxWords: number;
|
|
357
|
+
}, {
|
|
358
|
+
query: string;
|
|
359
|
+
maxResults?: number | undefined;
|
|
360
|
+
maxWords?: number | undefined;
|
|
361
|
+
}>, {
|
|
362
|
+
success: boolean;
|
|
363
|
+
error: string;
|
|
364
|
+
requiredEnvVars: string[];
|
|
365
|
+
query?: undefined;
|
|
366
|
+
searchResults?: undefined;
|
|
367
|
+
rawContent?: undefined;
|
|
368
|
+
totalResults?: undefined;
|
|
369
|
+
provider?: undefined;
|
|
370
|
+
model?: undefined;
|
|
371
|
+
responseTime?: undefined;
|
|
372
|
+
timestamp?: undefined;
|
|
373
|
+
grounded?: undefined;
|
|
374
|
+
} | {
|
|
375
|
+
success: boolean;
|
|
376
|
+
error: string;
|
|
377
|
+
query: string;
|
|
378
|
+
requiredEnvVars?: undefined;
|
|
379
|
+
searchResults?: undefined;
|
|
380
|
+
rawContent?: undefined;
|
|
381
|
+
totalResults?: undefined;
|
|
382
|
+
provider?: undefined;
|
|
383
|
+
model?: undefined;
|
|
384
|
+
responseTime?: undefined;
|
|
385
|
+
timestamp?: undefined;
|
|
386
|
+
grounded?: undefined;
|
|
387
|
+
} | {
|
|
388
|
+
success: boolean;
|
|
389
|
+
query: string;
|
|
390
|
+
searchResults: {
|
|
391
|
+
title: string;
|
|
392
|
+
url: string;
|
|
393
|
+
snippet: string;
|
|
394
|
+
domain: string;
|
|
395
|
+
}[];
|
|
396
|
+
rawContent: string;
|
|
397
|
+
totalResults: number;
|
|
398
|
+
provider: string;
|
|
399
|
+
model: string;
|
|
400
|
+
responseTime: number;
|
|
401
|
+
timestamp: number;
|
|
402
|
+
grounded: boolean;
|
|
403
|
+
error?: undefined;
|
|
404
|
+
requiredEnvVars?: undefined;
|
|
405
|
+
} | {
|
|
406
|
+
success: boolean;
|
|
407
|
+
error: string;
|
|
408
|
+
query: string;
|
|
409
|
+
provider: string;
|
|
410
|
+
requiredEnvVars?: undefined;
|
|
411
|
+
searchResults?: undefined;
|
|
412
|
+
rawContent?: undefined;
|
|
413
|
+
totalResults?: undefined;
|
|
414
|
+
model?: undefined;
|
|
415
|
+
responseTime?: undefined;
|
|
416
|
+
timestamp?: undefined;
|
|
417
|
+
grounded?: undefined;
|
|
418
|
+
}> & {
|
|
419
|
+
execute: (args: {
|
|
420
|
+
query: string;
|
|
421
|
+
maxResults: number;
|
|
422
|
+
maxWords: number;
|
|
423
|
+
}, options: import("ai").ToolExecutionOptions) => PromiseLike<{
|
|
424
|
+
success: boolean;
|
|
425
|
+
error: string;
|
|
426
|
+
requiredEnvVars: string[];
|
|
427
|
+
query?: undefined;
|
|
428
|
+
searchResults?: undefined;
|
|
429
|
+
rawContent?: undefined;
|
|
430
|
+
totalResults?: undefined;
|
|
431
|
+
provider?: undefined;
|
|
432
|
+
model?: undefined;
|
|
433
|
+
responseTime?: undefined;
|
|
434
|
+
timestamp?: undefined;
|
|
435
|
+
grounded?: undefined;
|
|
436
|
+
} | {
|
|
437
|
+
success: boolean;
|
|
438
|
+
error: string;
|
|
439
|
+
query: string;
|
|
440
|
+
requiredEnvVars?: undefined;
|
|
441
|
+
searchResults?: undefined;
|
|
442
|
+
rawContent?: undefined;
|
|
443
|
+
totalResults?: undefined;
|
|
444
|
+
provider?: undefined;
|
|
445
|
+
model?: undefined;
|
|
446
|
+
responseTime?: undefined;
|
|
447
|
+
timestamp?: undefined;
|
|
448
|
+
grounded?: undefined;
|
|
449
|
+
} | {
|
|
450
|
+
success: boolean;
|
|
451
|
+
query: string;
|
|
452
|
+
searchResults: {
|
|
453
|
+
title: string;
|
|
454
|
+
url: string;
|
|
455
|
+
snippet: string;
|
|
456
|
+
domain: string;
|
|
457
|
+
}[];
|
|
458
|
+
rawContent: string;
|
|
459
|
+
totalResults: number;
|
|
460
|
+
provider: string;
|
|
461
|
+
model: string;
|
|
462
|
+
responseTime: number;
|
|
463
|
+
timestamp: number;
|
|
464
|
+
grounded: boolean;
|
|
465
|
+
error?: undefined;
|
|
466
|
+
requiredEnvVars?: undefined;
|
|
467
|
+
} | {
|
|
468
|
+
success: boolean;
|
|
469
|
+
error: string;
|
|
470
|
+
query: string;
|
|
471
|
+
provider: string;
|
|
472
|
+
requiredEnvVars?: undefined;
|
|
473
|
+
searchResults?: undefined;
|
|
474
|
+
rawContent?: undefined;
|
|
475
|
+
totalResults?: undefined;
|
|
476
|
+
model?: undefined;
|
|
477
|
+
responseTime?: undefined;
|
|
478
|
+
timestamp?: undefined;
|
|
479
|
+
grounded?: undefined;
|
|
480
|
+
}>;
|
|
481
|
+
};
|
|
349
482
|
};
|
|
350
483
|
/**
|
|
351
484
|
* Type aliases for specific tool categories
|
|
@@ -7,6 +7,18 @@ import { z } from "zod";
|
|
|
7
7
|
import * as fs from "fs";
|
|
8
8
|
import * as path from "path";
|
|
9
9
|
import { logger } from "../utils/logger.js";
|
|
10
|
+
import { VertexAI } from "@google-cloud/vertexai";
|
|
11
|
+
// Runtime Google Search tool creation - bypasses TypeScript strict typing
|
|
12
|
+
function createGoogleSearchTools() {
|
|
13
|
+
const searchTool = {};
|
|
14
|
+
// Dynamically assign google_search property at runtime
|
|
15
|
+
Object.defineProperty(searchTool, "google_search", {
|
|
16
|
+
value: {},
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
});
|
|
20
|
+
return [searchTool];
|
|
21
|
+
}
|
|
10
22
|
/**
|
|
11
23
|
* Direct tool definitions that work immediately with Gemini/AI SDK
|
|
12
24
|
* These bypass MCP complexity and provide reliable agent functionality
|
|
@@ -324,6 +336,128 @@ export const directAgentTools = {
|
|
|
324
336
|
}
|
|
325
337
|
},
|
|
326
338
|
}),
|
|
339
|
+
websearchGrounding: tool({
|
|
340
|
+
description: "Search the web for current information using Google Search grounding. Returns raw search data for AI processing.",
|
|
341
|
+
parameters: z.object({
|
|
342
|
+
query: z.string().describe("Search query to find information about"),
|
|
343
|
+
maxResults: z
|
|
344
|
+
.number()
|
|
345
|
+
.optional()
|
|
346
|
+
.default(3)
|
|
347
|
+
.describe("Maximum number of search results to return (1-5)"),
|
|
348
|
+
maxWords: z
|
|
349
|
+
.number()
|
|
350
|
+
.optional()
|
|
351
|
+
.default(50)
|
|
352
|
+
.describe("Maximum number of words in the response 50"),
|
|
353
|
+
}),
|
|
354
|
+
execute: async ({ query, maxResults = 3, maxWords = 50 }) => {
|
|
355
|
+
try {
|
|
356
|
+
const hasCredentials = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
357
|
+
const hasProjectId = process.env.GOOGLE_VERTEX_PROJECT;
|
|
358
|
+
const projectLocation = process.env.GOOGLE_VERTEX_LOCATION || "us-central1";
|
|
359
|
+
if (!hasCredentials || !hasProjectId) {
|
|
360
|
+
return {
|
|
361
|
+
success: false,
|
|
362
|
+
error: "Google Vertex AI credentials not configured. Please set GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_VERTEX_PROJECT environment variables.",
|
|
363
|
+
requiredEnvVars: [
|
|
364
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
365
|
+
"GOOGLE_VERTEX_PROJECT",
|
|
366
|
+
],
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const limitedResults = Math.min(Math.max(maxResults, 1), 5);
|
|
370
|
+
const vertex_ai = new VertexAI({
|
|
371
|
+
project: hasProjectId,
|
|
372
|
+
location: projectLocation,
|
|
373
|
+
});
|
|
374
|
+
const websearchModel = "gemini-2.5-flash-lite";
|
|
375
|
+
const model = vertex_ai.getGenerativeModel({
|
|
376
|
+
model: websearchModel,
|
|
377
|
+
tools: createGoogleSearchTools(),
|
|
378
|
+
});
|
|
379
|
+
// Search query with word limit constraint
|
|
380
|
+
const searchPrompt = `Search for: "${query}". Provide a concise summary in no more than ${maxWords} words.`;
|
|
381
|
+
const startTime = Date.now();
|
|
382
|
+
const response = await model.generateContent({
|
|
383
|
+
contents: [
|
|
384
|
+
{
|
|
385
|
+
role: "user",
|
|
386
|
+
parts: [{ text: searchPrompt }],
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
});
|
|
390
|
+
const responseTime = Date.now() - startTime;
|
|
391
|
+
// Extract grounding metadata and search results
|
|
392
|
+
const result = response.response;
|
|
393
|
+
const candidates = result.candidates;
|
|
394
|
+
if (!candidates || candidates.length === 0) {
|
|
395
|
+
return {
|
|
396
|
+
success: false,
|
|
397
|
+
error: "No search results returned",
|
|
398
|
+
query,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
const content = candidates[0].content;
|
|
402
|
+
if (!content || !content.parts || content.parts.length === 0) {
|
|
403
|
+
return {
|
|
404
|
+
success: false,
|
|
405
|
+
error: "No search content found",
|
|
406
|
+
query,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
// Extract raw search content
|
|
410
|
+
const searchContent = content.parts[0].text || "";
|
|
411
|
+
// Extract grounding sources if available
|
|
412
|
+
const groundingMetadata = candidates[0]?.groundingMetadata;
|
|
413
|
+
const searchResults = [];
|
|
414
|
+
if (groundingMetadata?.groundingChunks) {
|
|
415
|
+
for (const chunk of groundingMetadata.groundingChunks.slice(0, limitedResults)) {
|
|
416
|
+
if (chunk.web) {
|
|
417
|
+
searchResults.push({
|
|
418
|
+
title: chunk.web.title || "No title",
|
|
419
|
+
url: chunk.web.uri || "",
|
|
420
|
+
snippet: searchContent, // Use full content since maxWords already limits length
|
|
421
|
+
domain: chunk.web.uri
|
|
422
|
+
? new URL(chunk.web.uri).hostname
|
|
423
|
+
: "unknown",
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// If no grounding metadata, create basic result structure
|
|
429
|
+
if (searchResults.length === 0) {
|
|
430
|
+
searchResults.push({
|
|
431
|
+
title: `Search results for: ${query}`,
|
|
432
|
+
url: "",
|
|
433
|
+
snippet: searchContent,
|
|
434
|
+
domain: "google-search",
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
success: true,
|
|
439
|
+
query,
|
|
440
|
+
searchResults,
|
|
441
|
+
rawContent: searchContent,
|
|
442
|
+
totalResults: searchResults.length,
|
|
443
|
+
provider: "google-search-grounding",
|
|
444
|
+
model: websearchModel,
|
|
445
|
+
responseTime,
|
|
446
|
+
timestamp: startTime,
|
|
447
|
+
grounded: true,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
logger.error("Web search grounding error:", error);
|
|
452
|
+
return {
|
|
453
|
+
success: false,
|
|
454
|
+
error: error instanceof Error ? error.message : String(error),
|
|
455
|
+
query,
|
|
456
|
+
provider: "google-search-grounding",
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
}),
|
|
327
461
|
};
|
|
328
462
|
// eslint-disable-next-line no-redeclare
|
|
329
463
|
export function getToolsForCategory(category = "all") {
|
|
@@ -346,6 +346,139 @@ export declare const directAgentTools: {
|
|
|
346
346
|
count?: undefined;
|
|
347
347
|
}>;
|
|
348
348
|
};
|
|
349
|
+
websearchGrounding: import("ai").Tool<z.ZodObject<{
|
|
350
|
+
query: z.ZodString;
|
|
351
|
+
maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
352
|
+
maxWords: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
353
|
+
}, "strip", z.ZodTypeAny, {
|
|
354
|
+
query: string;
|
|
355
|
+
maxResults: number;
|
|
356
|
+
maxWords: number;
|
|
357
|
+
}, {
|
|
358
|
+
query: string;
|
|
359
|
+
maxResults?: number | undefined;
|
|
360
|
+
maxWords?: number | undefined;
|
|
361
|
+
}>, {
|
|
362
|
+
success: boolean;
|
|
363
|
+
error: string;
|
|
364
|
+
requiredEnvVars: string[];
|
|
365
|
+
query?: undefined;
|
|
366
|
+
searchResults?: undefined;
|
|
367
|
+
rawContent?: undefined;
|
|
368
|
+
totalResults?: undefined;
|
|
369
|
+
provider?: undefined;
|
|
370
|
+
model?: undefined;
|
|
371
|
+
responseTime?: undefined;
|
|
372
|
+
timestamp?: undefined;
|
|
373
|
+
grounded?: undefined;
|
|
374
|
+
} | {
|
|
375
|
+
success: boolean;
|
|
376
|
+
error: string;
|
|
377
|
+
query: string;
|
|
378
|
+
requiredEnvVars?: undefined;
|
|
379
|
+
searchResults?: undefined;
|
|
380
|
+
rawContent?: undefined;
|
|
381
|
+
totalResults?: undefined;
|
|
382
|
+
provider?: undefined;
|
|
383
|
+
model?: undefined;
|
|
384
|
+
responseTime?: undefined;
|
|
385
|
+
timestamp?: undefined;
|
|
386
|
+
grounded?: undefined;
|
|
387
|
+
} | {
|
|
388
|
+
success: boolean;
|
|
389
|
+
query: string;
|
|
390
|
+
searchResults: {
|
|
391
|
+
title: string;
|
|
392
|
+
url: string;
|
|
393
|
+
snippet: string;
|
|
394
|
+
domain: string;
|
|
395
|
+
}[];
|
|
396
|
+
rawContent: string;
|
|
397
|
+
totalResults: number;
|
|
398
|
+
provider: string;
|
|
399
|
+
model: string;
|
|
400
|
+
responseTime: number;
|
|
401
|
+
timestamp: number;
|
|
402
|
+
grounded: boolean;
|
|
403
|
+
error?: undefined;
|
|
404
|
+
requiredEnvVars?: undefined;
|
|
405
|
+
} | {
|
|
406
|
+
success: boolean;
|
|
407
|
+
error: string;
|
|
408
|
+
query: string;
|
|
409
|
+
provider: string;
|
|
410
|
+
requiredEnvVars?: undefined;
|
|
411
|
+
searchResults?: undefined;
|
|
412
|
+
rawContent?: undefined;
|
|
413
|
+
totalResults?: undefined;
|
|
414
|
+
model?: undefined;
|
|
415
|
+
responseTime?: undefined;
|
|
416
|
+
timestamp?: undefined;
|
|
417
|
+
grounded?: undefined;
|
|
418
|
+
}> & {
|
|
419
|
+
execute: (args: {
|
|
420
|
+
query: string;
|
|
421
|
+
maxResults: number;
|
|
422
|
+
maxWords: number;
|
|
423
|
+
}, options: import("ai").ToolExecutionOptions) => PromiseLike<{
|
|
424
|
+
success: boolean;
|
|
425
|
+
error: string;
|
|
426
|
+
requiredEnvVars: string[];
|
|
427
|
+
query?: undefined;
|
|
428
|
+
searchResults?: undefined;
|
|
429
|
+
rawContent?: undefined;
|
|
430
|
+
totalResults?: undefined;
|
|
431
|
+
provider?: undefined;
|
|
432
|
+
model?: undefined;
|
|
433
|
+
responseTime?: undefined;
|
|
434
|
+
timestamp?: undefined;
|
|
435
|
+
grounded?: undefined;
|
|
436
|
+
} | {
|
|
437
|
+
success: boolean;
|
|
438
|
+
error: string;
|
|
439
|
+
query: string;
|
|
440
|
+
requiredEnvVars?: undefined;
|
|
441
|
+
searchResults?: undefined;
|
|
442
|
+
rawContent?: undefined;
|
|
443
|
+
totalResults?: undefined;
|
|
444
|
+
provider?: undefined;
|
|
445
|
+
model?: undefined;
|
|
446
|
+
responseTime?: undefined;
|
|
447
|
+
timestamp?: undefined;
|
|
448
|
+
grounded?: undefined;
|
|
449
|
+
} | {
|
|
450
|
+
success: boolean;
|
|
451
|
+
query: string;
|
|
452
|
+
searchResults: {
|
|
453
|
+
title: string;
|
|
454
|
+
url: string;
|
|
455
|
+
snippet: string;
|
|
456
|
+
domain: string;
|
|
457
|
+
}[];
|
|
458
|
+
rawContent: string;
|
|
459
|
+
totalResults: number;
|
|
460
|
+
provider: string;
|
|
461
|
+
model: string;
|
|
462
|
+
responseTime: number;
|
|
463
|
+
timestamp: number;
|
|
464
|
+
grounded: boolean;
|
|
465
|
+
error?: undefined;
|
|
466
|
+
requiredEnvVars?: undefined;
|
|
467
|
+
} | {
|
|
468
|
+
success: boolean;
|
|
469
|
+
error: string;
|
|
470
|
+
query: string;
|
|
471
|
+
provider: string;
|
|
472
|
+
requiredEnvVars?: undefined;
|
|
473
|
+
searchResults?: undefined;
|
|
474
|
+
rawContent?: undefined;
|
|
475
|
+
totalResults?: undefined;
|
|
476
|
+
model?: undefined;
|
|
477
|
+
responseTime?: undefined;
|
|
478
|
+
timestamp?: undefined;
|
|
479
|
+
grounded?: undefined;
|
|
480
|
+
}>;
|
|
481
|
+
};
|
|
349
482
|
};
|
|
350
483
|
/**
|
|
351
484
|
* Type aliases for specific tool categories
|
|
@@ -7,6 +7,18 @@ import { z } from "zod";
|
|
|
7
7
|
import * as fs from "fs";
|
|
8
8
|
import * as path from "path";
|
|
9
9
|
import { logger } from "../utils/logger.js";
|
|
10
|
+
import { VertexAI } from "@google-cloud/vertexai";
|
|
11
|
+
// Runtime Google Search tool creation - bypasses TypeScript strict typing
|
|
12
|
+
function createGoogleSearchTools() {
|
|
13
|
+
const searchTool = {};
|
|
14
|
+
// Dynamically assign google_search property at runtime
|
|
15
|
+
Object.defineProperty(searchTool, "google_search", {
|
|
16
|
+
value: {},
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
});
|
|
20
|
+
return [searchTool];
|
|
21
|
+
}
|
|
10
22
|
/**
|
|
11
23
|
* Direct tool definitions that work immediately with Gemini/AI SDK
|
|
12
24
|
* These bypass MCP complexity and provide reliable agent functionality
|
|
@@ -324,6 +336,128 @@ export const directAgentTools = {
|
|
|
324
336
|
}
|
|
325
337
|
},
|
|
326
338
|
}),
|
|
339
|
+
websearchGrounding: tool({
|
|
340
|
+
description: "Search the web for current information using Google Search grounding. Returns raw search data for AI processing.",
|
|
341
|
+
parameters: z.object({
|
|
342
|
+
query: z.string().describe("Search query to find information about"),
|
|
343
|
+
maxResults: z
|
|
344
|
+
.number()
|
|
345
|
+
.optional()
|
|
346
|
+
.default(3)
|
|
347
|
+
.describe("Maximum number of search results to return (1-5)"),
|
|
348
|
+
maxWords: z
|
|
349
|
+
.number()
|
|
350
|
+
.optional()
|
|
351
|
+
.default(50)
|
|
352
|
+
.describe("Maximum number of words in the response 50"),
|
|
353
|
+
}),
|
|
354
|
+
execute: async ({ query, maxResults = 3, maxWords = 50 }) => {
|
|
355
|
+
try {
|
|
356
|
+
const hasCredentials = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
357
|
+
const hasProjectId = process.env.GOOGLE_VERTEX_PROJECT;
|
|
358
|
+
const projectLocation = process.env.GOOGLE_VERTEX_LOCATION || "us-central1";
|
|
359
|
+
if (!hasCredentials || !hasProjectId) {
|
|
360
|
+
return {
|
|
361
|
+
success: false,
|
|
362
|
+
error: "Google Vertex AI credentials not configured. Please set GOOGLE_APPLICATION_CREDENTIALS and GOOGLE_VERTEX_PROJECT environment variables.",
|
|
363
|
+
requiredEnvVars: [
|
|
364
|
+
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
365
|
+
"GOOGLE_VERTEX_PROJECT",
|
|
366
|
+
],
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
const limitedResults = Math.min(Math.max(maxResults, 1), 5);
|
|
370
|
+
const vertex_ai = new VertexAI({
|
|
371
|
+
project: hasProjectId,
|
|
372
|
+
location: projectLocation,
|
|
373
|
+
});
|
|
374
|
+
const websearchModel = "gemini-2.5-flash-lite";
|
|
375
|
+
const model = vertex_ai.getGenerativeModel({
|
|
376
|
+
model: websearchModel,
|
|
377
|
+
tools: createGoogleSearchTools(),
|
|
378
|
+
});
|
|
379
|
+
// Search query with word limit constraint
|
|
380
|
+
const searchPrompt = `Search for: "${query}". Provide a concise summary in no more than ${maxWords} words.`;
|
|
381
|
+
const startTime = Date.now();
|
|
382
|
+
const response = await model.generateContent({
|
|
383
|
+
contents: [
|
|
384
|
+
{
|
|
385
|
+
role: "user",
|
|
386
|
+
parts: [{ text: searchPrompt }],
|
|
387
|
+
},
|
|
388
|
+
],
|
|
389
|
+
});
|
|
390
|
+
const responseTime = Date.now() - startTime;
|
|
391
|
+
// Extract grounding metadata and search results
|
|
392
|
+
const result = response.response;
|
|
393
|
+
const candidates = result.candidates;
|
|
394
|
+
if (!candidates || candidates.length === 0) {
|
|
395
|
+
return {
|
|
396
|
+
success: false,
|
|
397
|
+
error: "No search results returned",
|
|
398
|
+
query,
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
const content = candidates[0].content;
|
|
402
|
+
if (!content || !content.parts || content.parts.length === 0) {
|
|
403
|
+
return {
|
|
404
|
+
success: false,
|
|
405
|
+
error: "No search content found",
|
|
406
|
+
query,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
// Extract raw search content
|
|
410
|
+
const searchContent = content.parts[0].text || "";
|
|
411
|
+
// Extract grounding sources if available
|
|
412
|
+
const groundingMetadata = candidates[0]?.groundingMetadata;
|
|
413
|
+
const searchResults = [];
|
|
414
|
+
if (groundingMetadata?.groundingChunks) {
|
|
415
|
+
for (const chunk of groundingMetadata.groundingChunks.slice(0, limitedResults)) {
|
|
416
|
+
if (chunk.web) {
|
|
417
|
+
searchResults.push({
|
|
418
|
+
title: chunk.web.title || "No title",
|
|
419
|
+
url: chunk.web.uri || "",
|
|
420
|
+
snippet: searchContent, // Use full content since maxWords already limits length
|
|
421
|
+
domain: chunk.web.uri
|
|
422
|
+
? new URL(chunk.web.uri).hostname
|
|
423
|
+
: "unknown",
|
|
424
|
+
});
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// If no grounding metadata, create basic result structure
|
|
429
|
+
if (searchResults.length === 0) {
|
|
430
|
+
searchResults.push({
|
|
431
|
+
title: `Search results for: ${query}`,
|
|
432
|
+
url: "",
|
|
433
|
+
snippet: searchContent,
|
|
434
|
+
domain: "google-search",
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
return {
|
|
438
|
+
success: true,
|
|
439
|
+
query,
|
|
440
|
+
searchResults,
|
|
441
|
+
rawContent: searchContent,
|
|
442
|
+
totalResults: searchResults.length,
|
|
443
|
+
provider: "google-search-grounding",
|
|
444
|
+
model: websearchModel,
|
|
445
|
+
responseTime,
|
|
446
|
+
timestamp: startTime,
|
|
447
|
+
grounded: true,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
catch (error) {
|
|
451
|
+
logger.error("Web search grounding error:", error);
|
|
452
|
+
return {
|
|
453
|
+
success: false,
|
|
454
|
+
error: error instanceof Error ? error.message : String(error),
|
|
455
|
+
query,
|
|
456
|
+
provider: "google-search-grounding",
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
},
|
|
460
|
+
}),
|
|
327
461
|
};
|
|
328
462
|
// eslint-disable-next-line no-redeclare
|
|
329
463
|
export function getToolsForCategory(category = "all") {
|
package/dist/lib/neurolink.js
CHANGED
|
@@ -32,6 +32,8 @@ import { EventEmitter } from "events";
|
|
|
32
32
|
import { ConversationMemoryManager } from "./core/conversationMemoryManager.js";
|
|
33
33
|
import { applyConversationMemoryDefaults, getConversationMessages, storeConversationTurn, } from "./utils/conversationMemoryUtils.js";
|
|
34
34
|
import { ExternalServerManager } from "./mcp/externalServerManager.js";
|
|
35
|
+
// Import direct tools server for automatic registration
|
|
36
|
+
import { directToolsServer } from "./mcp/servers/agent/directToolsServer.js";
|
|
35
37
|
import { ContextManager } from "./context/ContextManager.js";
|
|
36
38
|
import { defaultContextConfig } from "./context/config.js";
|
|
37
39
|
import { isNonNullObject } from "./utils/typeUtils.js";
|
|
@@ -130,6 +132,19 @@ export class NeuroLink {
|
|
|
130
132
|
]);
|
|
131
133
|
// Register all providers with lazy loading support
|
|
132
134
|
await ProviderRegistry.registerAllProviders();
|
|
135
|
+
// Register the direct tools server to make websearch and other tools available
|
|
136
|
+
try {
|
|
137
|
+
// Use the server ID string for registration instead of the server object
|
|
138
|
+
await toolRegistry.registerServer("neurolink-direct", directToolsServer);
|
|
139
|
+
mcpLogger.debug("[NeuroLink] Direct tools server registered successfully", {
|
|
140
|
+
serverId: "neurolink-direct",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
mcpLogger.warn("[NeuroLink] Failed to register direct tools server", {
|
|
145
|
+
error: error instanceof Error ? error.message : String(error),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
133
148
|
// Load MCP configuration from .mcp-config.json using ExternalServerManager
|
|
134
149
|
try {
|
|
135
150
|
const configResult = await this.externalServerManager.loadMCPConfiguration();
|
package/dist/neurolink.js
CHANGED
|
@@ -32,6 +32,8 @@ import { EventEmitter } from "events";
|
|
|
32
32
|
import { ConversationMemoryManager } from "./core/conversationMemoryManager.js";
|
|
33
33
|
import { applyConversationMemoryDefaults, getConversationMessages, storeConversationTurn, } from "./utils/conversationMemoryUtils.js";
|
|
34
34
|
import { ExternalServerManager } from "./mcp/externalServerManager.js";
|
|
35
|
+
// Import direct tools server for automatic registration
|
|
36
|
+
import { directToolsServer } from "./mcp/servers/agent/directToolsServer.js";
|
|
35
37
|
import { ContextManager } from "./context/ContextManager.js";
|
|
36
38
|
import { defaultContextConfig } from "./context/config.js";
|
|
37
39
|
import { isNonNullObject } from "./utils/typeUtils.js";
|
|
@@ -130,6 +132,19 @@ export class NeuroLink {
|
|
|
130
132
|
]);
|
|
131
133
|
// Register all providers with lazy loading support
|
|
132
134
|
await ProviderRegistry.registerAllProviders();
|
|
135
|
+
// Register the direct tools server to make websearch and other tools available
|
|
136
|
+
try {
|
|
137
|
+
// Use the server ID string for registration instead of the server object
|
|
138
|
+
await toolRegistry.registerServer("neurolink-direct", directToolsServer);
|
|
139
|
+
mcpLogger.debug("[NeuroLink] Direct tools server registered successfully", {
|
|
140
|
+
serverId: "neurolink-direct",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
mcpLogger.warn("[NeuroLink] Failed to register direct tools server", {
|
|
145
|
+
error: error instanceof Error ? error.message : String(error),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
133
148
|
// Load MCP configuration from .mcp-config.json using ExternalServerManager
|
|
134
149
|
try {
|
|
135
150
|
const configResult = await this.externalServerManager.loadMCPConfiguration();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.15.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",
|
|
@@ -148,6 +148,7 @@
|
|
|
148
148
|
"@aws-sdk/client-sagemaker": "^3.862.0",
|
|
149
149
|
"@aws-sdk/client-sagemaker-runtime": "^3.862.0",
|
|
150
150
|
"@aws-sdk/types": "^3.862.0",
|
|
151
|
+
"@google-cloud/vertexai": "^1.10.0",
|
|
151
152
|
"@google/generative-ai": "^0.24.1",
|
|
152
153
|
"@huggingface/inference": "^2.8.0",
|
|
153
154
|
"@modelcontextprotocol/sdk": "^1.13.0",
|