@juspay/neurolink 2.1.0 → 3.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 +29 -9
- package/README.md +17 -39
- package/dist/cli/index.js +28 -16
- package/dist/lib/mcp/plugins/filesystem-mcp.d.ts +1 -1
- package/dist/lib/providers/agent-enhanced-provider.js +61 -53
- package/dist/lib/providers/amazonBedrock.js +11 -7
- package/dist/lib/providers/anthropic.js +13 -11
- package/dist/lib/providers/azureOpenAI.js +10 -10
- package/dist/lib/providers/googleAIStudio.js +14 -7
- package/dist/lib/providers/googleVertexAI.js +14 -7
- package/dist/lib/providers/huggingFace.js +11 -7
- package/dist/lib/providers/mistralAI.js +11 -7
- package/dist/lib/providers/ollama.js +12 -4
- package/dist/lib/providers/openAI.js +11 -7
- package/dist/lib/providers/timeout-wrapper.d.ts +2 -2
- package/dist/lib/providers/timeout-wrapper.js +3 -3
- package/dist/lib/proxy/proxy-fetch.d.ts +18 -0
- package/dist/lib/proxy/proxy-fetch.js +64 -0
- package/dist/lib/utils/timeout.d.ts +4 -4
- package/dist/lib/utils/timeout.js +42 -34
- package/dist/mcp/plugins/filesystem-mcp.d.ts +1 -1
- package/dist/mcp/plugins/filesystem-mcp.js +1 -1
- package/dist/providers/agent-enhanced-provider.js +61 -53
- package/dist/providers/amazonBedrock.js +11 -7
- package/dist/providers/anthropic.js +13 -11
- package/dist/providers/azureOpenAI.js +10 -10
- package/dist/providers/googleAIStudio.js +14 -7
- package/dist/providers/googleVertexAI.js +14 -7
- package/dist/providers/huggingFace.js +11 -7
- package/dist/providers/mistralAI.js +11 -7
- package/dist/providers/ollama.js +12 -4
- package/dist/providers/openAI.js +11 -7
- package/dist/providers/timeout-wrapper.d.ts +2 -2
- package/dist/providers/timeout-wrapper.js +3 -3
- package/dist/proxy/proxy-fetch.d.ts +18 -0
- package/dist/proxy/proxy-fetch.js +64 -0
- package/dist/utils/timeout.d.ts +4 -4
- package/dist/utils/timeout.js +42 -34
- package/package.json +2 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Proxy-aware fetch implementation for AI SDK providers
|
|
3
|
+
* Implements the proven Vercel AI SDK proxy pattern using undici
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Create a proxy-aware fetch function
|
|
7
|
+
* This implements the community-validated approach for Vercel AI SDK
|
|
8
|
+
*/
|
|
9
|
+
export function createProxyFetch() {
|
|
10
|
+
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
11
|
+
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
|
12
|
+
// If no proxy configured, return standard fetch
|
|
13
|
+
if (!httpsProxy && !httpProxy) {
|
|
14
|
+
console.log("[Proxy Fetch] No proxy environment variables found - using standard fetch");
|
|
15
|
+
return fetch;
|
|
16
|
+
}
|
|
17
|
+
console.log(`[Proxy Fetch] Configuring proxy with undici ProxyAgent:`);
|
|
18
|
+
console.log(`[Proxy Fetch] HTTP_PROXY: ${httpProxy || "not set"}`);
|
|
19
|
+
console.log(`[Proxy Fetch] HTTPS_PROXY: ${httpsProxy || "not set"}`);
|
|
20
|
+
// Return proxy-aware fetch function
|
|
21
|
+
return async (input, init) => {
|
|
22
|
+
try {
|
|
23
|
+
// Dynamic import undici to avoid build issues
|
|
24
|
+
const undici = await import("undici");
|
|
25
|
+
const { ProxyAgent } = undici;
|
|
26
|
+
const url = typeof input === "string"
|
|
27
|
+
? new URL(input)
|
|
28
|
+
: input instanceof URL
|
|
29
|
+
? input
|
|
30
|
+
: new URL(input.url);
|
|
31
|
+
const proxyUrl = url.protocol === "https:" ? httpsProxy : httpProxy;
|
|
32
|
+
if (proxyUrl) {
|
|
33
|
+
console.log(`[Proxy Fetch] Creating ProxyAgent for ${url.hostname} via ${proxyUrl}`);
|
|
34
|
+
// Create ProxyAgent
|
|
35
|
+
const dispatcher = new ProxyAgent(proxyUrl);
|
|
36
|
+
// Use undici fetch with dispatcher
|
|
37
|
+
const response = await undici.fetch(input, {
|
|
38
|
+
...init,
|
|
39
|
+
dispatcher: dispatcher,
|
|
40
|
+
});
|
|
41
|
+
console.log(`[Proxy Fetch] ✅ Request proxied successfully to ${url.hostname}`);
|
|
42
|
+
return response; // Type assertion to avoid complex type issues
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
console.warn(`[Proxy Fetch] Proxy failed (${error.message}), falling back to direct connection`);
|
|
47
|
+
}
|
|
48
|
+
// Fallback to standard fetch
|
|
49
|
+
return fetch(input, init);
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Get proxy status information
|
|
54
|
+
*/
|
|
55
|
+
export function getProxyStatus() {
|
|
56
|
+
const httpsProxy = process.env.HTTPS_PROXY || process.env.https_proxy;
|
|
57
|
+
const httpProxy = process.env.HTTP_PROXY || process.env.http_proxy;
|
|
58
|
+
return {
|
|
59
|
+
enabled: !!(httpsProxy || httpProxy),
|
|
60
|
+
httpProxy: httpProxy || null,
|
|
61
|
+
httpsProxy: httpsProxy || null,
|
|
62
|
+
method: "undici-proxy-agent",
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -39,7 +39,7 @@ export declare const DEFAULT_TIMEOUTS: {
|
|
|
39
39
|
vertex: string;
|
|
40
40
|
anthropic: string;
|
|
41
41
|
azure: string;
|
|
42
|
-
|
|
42
|
+
"google-ai": string;
|
|
43
43
|
huggingface: string;
|
|
44
44
|
ollama: string;
|
|
45
45
|
mistral: string;
|
|
@@ -57,7 +57,7 @@ export declare const DEFAULT_TIMEOUTS: {
|
|
|
57
57
|
* @param operation - Operation type (generate or stream)
|
|
58
58
|
* @returns Default timeout string
|
|
59
59
|
*/
|
|
60
|
-
export declare function getDefaultTimeout(provider: string, operation?:
|
|
60
|
+
export declare function getDefaultTimeout(provider: string, operation?: "generate" | "stream"): string;
|
|
61
61
|
/**
|
|
62
62
|
* Create a timeout promise that rejects after specified duration
|
|
63
63
|
* @param timeout - Timeout duration
|
|
@@ -65,5 +65,5 @@ export declare function getDefaultTimeout(provider: string, operation?: 'generat
|
|
|
65
65
|
* @param operation - Operation type for error message
|
|
66
66
|
* @returns Promise that rejects with TimeoutError
|
|
67
67
|
*/
|
|
68
|
-
export declare function createTimeoutPromise(timeout: number | string | undefined, provider: string, operation:
|
|
69
|
-
export { createTimeoutController } from
|
|
68
|
+
export declare function createTimeoutPromise(timeout: number | string | undefined, provider: string, operation: "generate" | "stream"): Promise<never> | null;
|
|
69
|
+
export { createTimeoutController } from "../providers/timeout-wrapper.js";
|
|
@@ -16,9 +16,9 @@ export class TimeoutError extends Error {
|
|
|
16
16
|
this.timeout = timeout;
|
|
17
17
|
this.provider = provider;
|
|
18
18
|
this.operation = operation;
|
|
19
|
-
this.name =
|
|
19
|
+
this.name = "TimeoutError";
|
|
20
20
|
// Maintains proper stack trace for where error was thrown
|
|
21
|
-
if (typeof Error.captureStackTrace ===
|
|
21
|
+
if (typeof Error.captureStackTrace === "function") {
|
|
22
22
|
Error.captureStackTrace(this, TimeoutError);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -37,15 +37,16 @@ export class TimeoutError extends Error {
|
|
|
37
37
|
* - parseTimeout(undefined) => undefined
|
|
38
38
|
*/
|
|
39
39
|
export function parseTimeout(timeout) {
|
|
40
|
-
if (timeout === undefined)
|
|
40
|
+
if (timeout === undefined) {
|
|
41
41
|
return undefined;
|
|
42
|
-
|
|
42
|
+
}
|
|
43
|
+
if (typeof timeout === "number") {
|
|
43
44
|
if (timeout <= 0) {
|
|
44
45
|
throw new Error(`Timeout must be positive, got: ${timeout}`);
|
|
45
46
|
}
|
|
46
47
|
return timeout; // Assume milliseconds
|
|
47
48
|
}
|
|
48
|
-
if (typeof timeout ===
|
|
49
|
+
if (typeof timeout === "string") {
|
|
49
50
|
// Match number (including decimals) followed by optional unit
|
|
50
51
|
const match = timeout.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/);
|
|
51
52
|
if (!match) {
|
|
@@ -55,13 +56,18 @@ export function parseTimeout(timeout) {
|
|
|
55
56
|
if (value <= 0) {
|
|
56
57
|
throw new Error(`Timeout must be positive, got: ${value}`);
|
|
57
58
|
}
|
|
58
|
-
const unit = match[2] ||
|
|
59
|
+
const unit = match[2] || "ms";
|
|
59
60
|
switch (unit) {
|
|
60
|
-
case
|
|
61
|
-
|
|
62
|
-
case
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
case "ms":
|
|
62
|
+
return value;
|
|
63
|
+
case "s":
|
|
64
|
+
return value * 1000;
|
|
65
|
+
case "m":
|
|
66
|
+
return value * 60 * 1000;
|
|
67
|
+
case "h":
|
|
68
|
+
return value * 60 * 60 * 1000;
|
|
69
|
+
default:
|
|
70
|
+
return value; // Should never reach here due to regex
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
73
|
throw new Error(`Invalid timeout type: ${typeof timeout}`);
|
|
@@ -70,25 +76,25 @@ export function parseTimeout(timeout) {
|
|
|
70
76
|
* Default timeout configurations for different providers and operations
|
|
71
77
|
*/
|
|
72
78
|
export const DEFAULT_TIMEOUTS = {
|
|
73
|
-
global:
|
|
74
|
-
streaming:
|
|
79
|
+
global: "30s", // Default for all providers
|
|
80
|
+
streaming: "2m", // Longer timeout for streaming operations
|
|
75
81
|
providers: {
|
|
76
|
-
openai:
|
|
77
|
-
bedrock:
|
|
78
|
-
vertex:
|
|
79
|
-
anthropic:
|
|
80
|
-
azure:
|
|
81
|
-
|
|
82
|
-
huggingface:
|
|
83
|
-
ollama:
|
|
84
|
-
mistral:
|
|
82
|
+
openai: "30s", // OpenAI typically responds quickly
|
|
83
|
+
bedrock: "45s", // AWS can be slower, especially for cold starts
|
|
84
|
+
vertex: "60s", // Google Cloud can be slower
|
|
85
|
+
anthropic: "30s", // Direct Anthropic API is fast
|
|
86
|
+
azure: "30s", // Azure OpenAI similar to OpenAI
|
|
87
|
+
"google-ai": "30s", // Google AI Studio is fast
|
|
88
|
+
huggingface: "2m", // Open source models vary significantly
|
|
89
|
+
ollama: "5m", // Local models need more time, especially large ones
|
|
90
|
+
mistral: "45s", // Mistral AI moderate speed
|
|
85
91
|
},
|
|
86
92
|
tools: {
|
|
87
|
-
default:
|
|
88
|
-
filesystem:
|
|
89
|
-
network:
|
|
90
|
-
computation:
|
|
91
|
-
}
|
|
93
|
+
default: "10s", // Default timeout for MCP tool execution
|
|
94
|
+
filesystem: "5s", // File operations should be quick
|
|
95
|
+
network: "30s", // Network requests might take longer
|
|
96
|
+
computation: "2m", // Heavy computation tools need more time
|
|
97
|
+
},
|
|
92
98
|
};
|
|
93
99
|
/**
|
|
94
100
|
* Get default timeout for a specific provider
|
|
@@ -96,13 +102,12 @@ export const DEFAULT_TIMEOUTS = {
|
|
|
96
102
|
* @param operation - Operation type (generate or stream)
|
|
97
103
|
* @returns Default timeout string
|
|
98
104
|
*/
|
|
99
|
-
export function getDefaultTimeout(provider, operation =
|
|
100
|
-
if (operation ===
|
|
105
|
+
export function getDefaultTimeout(provider, operation = "generate") {
|
|
106
|
+
if (operation === "stream") {
|
|
101
107
|
return DEFAULT_TIMEOUTS.streaming;
|
|
102
108
|
}
|
|
103
|
-
const providerKey = provider.toLowerCase().replace(
|
|
104
|
-
return DEFAULT_TIMEOUTS.providers[providerKey]
|
|
105
|
-
|| DEFAULT_TIMEOUTS.global;
|
|
109
|
+
const providerKey = provider.toLowerCase().replace("_", "-");
|
|
110
|
+
return (DEFAULT_TIMEOUTS.providers[providerKey] || DEFAULT_TIMEOUTS.global);
|
|
106
111
|
}
|
|
107
112
|
/**
|
|
108
113
|
* Create a timeout promise that rejects after specified duration
|
|
@@ -121,10 +126,13 @@ export function createTimeoutPromise(timeout, provider, operation) {
|
|
|
121
126
|
reject(new TimeoutError(`${provider} ${operation} operation timed out after ${timeout}`, timeoutMs, provider, operation));
|
|
122
127
|
}, timeoutMs);
|
|
123
128
|
// Unref the timer so it doesn't keep the process alive (Node.js only)
|
|
124
|
-
if (typeof timer ===
|
|
129
|
+
if (typeof timer === "object" &&
|
|
130
|
+
timer &&
|
|
131
|
+
"unref" in timer &&
|
|
132
|
+
typeof timer.unref === "function") {
|
|
125
133
|
timer.unref();
|
|
126
134
|
}
|
|
127
135
|
});
|
|
128
136
|
}
|
|
129
137
|
// Re-export createTimeoutController from timeout-wrapper for convenience
|
|
130
|
-
export { createTimeoutController } from
|
|
138
|
+
export { createTimeoutController } from "../providers/timeout-wrapper.js";
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* Implements the new MCP contract with security sandbox
|
|
4
4
|
* Based on research document recommendations
|
|
5
5
|
*/
|
|
6
|
-
import { MCP, MCPMetadata, ExecutionContext } from "../contracts/mcp-contract.js";
|
|
6
|
+
import { MCP, type MCPMetadata, type ExecutionContext } from "../contracts/mcp-contract.js";
|
|
7
7
|
/**
|
|
8
8
|
* FileSystem MCP Configuration
|
|
9
9
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Based on research document recommendations
|
|
5
5
|
*/
|
|
6
6
|
import path from "path";
|
|
7
|
-
import { MCP,
|
|
7
|
+
import { MCP, MCPCategory, } from "../contracts/mcp-contract.js";
|
|
8
8
|
/**
|
|
9
9
|
* Enhanced FileSystem MCP Plugin
|
|
10
10
|
*/
|
|
@@ -66,14 +66,15 @@ export class AgentEnhancedProvider {
|
|
|
66
66
|
try {
|
|
67
67
|
mcpLogger.info("[AgentEnhancedProvider] Initializing MCP integration...");
|
|
68
68
|
this.mcpSystem = new UnifiedMCPSystem({
|
|
69
|
-
configPath: this.config.mcpDiscoveryOptions?.configFiles?.[0] ||
|
|
69
|
+
configPath: this.config.mcpDiscoveryOptions?.configFiles?.[0] ||
|
|
70
|
+
".mcp-config.json",
|
|
70
71
|
enableExternalServers: true,
|
|
71
72
|
enableInternalServers: true,
|
|
72
|
-
autoInitialize: false
|
|
73
|
+
autoInitialize: false,
|
|
73
74
|
});
|
|
74
75
|
// ADD TIMEOUT to prevent hanging forever
|
|
75
76
|
const initPromise = this.mcpSystem.initialize();
|
|
76
|
-
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error(
|
|
77
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("MCP initialization timeout after 15 seconds")), this.config.mcpInitTimeoutMs || 15000));
|
|
77
78
|
await Promise.race([initPromise, timeoutPromise]);
|
|
78
79
|
this.mcpInitialized = true;
|
|
79
80
|
mcpLogger.info("[AgentEnhancedProvider] MCP integration initialized successfully");
|
|
@@ -101,10 +102,13 @@ export class AgentEnhancedProvider {
|
|
|
101
102
|
return directTools;
|
|
102
103
|
}
|
|
103
104
|
// Get MCP tools if available
|
|
104
|
-
|
|
105
|
+
const mcpTools = {};
|
|
105
106
|
try {
|
|
106
107
|
// Skip if MCP failed to initialize or is still initializing
|
|
107
|
-
if (this.mcpInitFailed ||
|
|
108
|
+
if (this.mcpInitFailed ||
|
|
109
|
+
this.mcpInitializing ||
|
|
110
|
+
!this.mcpInitialized ||
|
|
111
|
+
!this.mcpSystem) {
|
|
108
112
|
return directTools;
|
|
109
113
|
}
|
|
110
114
|
const mcpToolInfos = await this.mcpSystem.listTools();
|
|
@@ -123,7 +127,7 @@ export class AgentEnhancedProvider {
|
|
|
123
127
|
? new AbortController()
|
|
124
128
|
: undefined;
|
|
125
129
|
if (toolAbortController && toolTimeout) {
|
|
126
|
-
const timeoutMs = typeof toolTimeout ===
|
|
130
|
+
const timeoutMs = typeof toolTimeout === "string"
|
|
127
131
|
? parseTimeout(toolTimeout)
|
|
128
132
|
: toolTimeout;
|
|
129
133
|
timeoutId = setTimeout(() => {
|
|
@@ -131,31 +135,35 @@ export class AgentEnhancedProvider {
|
|
|
131
135
|
}, timeoutMs);
|
|
132
136
|
}
|
|
133
137
|
const context = {
|
|
134
|
-
sessionId:
|
|
135
|
-
userId:
|
|
138
|
+
sessionId: "cli-session",
|
|
139
|
+
userId: "cli-user",
|
|
136
140
|
secureFS: {
|
|
137
141
|
readFile: async (path, encoding) => {
|
|
138
|
-
const fs = await import(
|
|
139
|
-
return encoding
|
|
142
|
+
const fs = await import("fs/promises");
|
|
143
|
+
return encoding
|
|
144
|
+
? fs.readFile(path, {
|
|
145
|
+
encoding: encoding,
|
|
146
|
+
})
|
|
147
|
+
: fs.readFile(path);
|
|
140
148
|
},
|
|
141
149
|
writeFile: async (path, content) => {
|
|
142
|
-
const fs = await import(
|
|
150
|
+
const fs = await import("fs/promises");
|
|
143
151
|
await fs.writeFile(path, content);
|
|
144
152
|
},
|
|
145
153
|
readdir: async (path) => {
|
|
146
|
-
const fs = await import(
|
|
154
|
+
const fs = await import("fs/promises");
|
|
147
155
|
return fs.readdir(path);
|
|
148
156
|
},
|
|
149
157
|
stat: async (path) => {
|
|
150
|
-
const fs = await import(
|
|
158
|
+
const fs = await import("fs/promises");
|
|
151
159
|
return fs.stat(path);
|
|
152
160
|
},
|
|
153
161
|
mkdir: async (path, options) => {
|
|
154
|
-
const fs = await import(
|
|
162
|
+
const fs = await import("fs/promises");
|
|
155
163
|
await fs.mkdir(path, options);
|
|
156
164
|
},
|
|
157
165
|
exists: async (path) => {
|
|
158
|
-
const fs = await import(
|
|
166
|
+
const fs = await import("fs/promises");
|
|
159
167
|
try {
|
|
160
168
|
await fs.access(path);
|
|
161
169
|
return true;
|
|
@@ -163,34 +171,34 @@ export class AgentEnhancedProvider {
|
|
|
163
171
|
catch {
|
|
164
172
|
return false;
|
|
165
173
|
}
|
|
166
|
-
}
|
|
174
|
+
},
|
|
167
175
|
},
|
|
168
176
|
path: {
|
|
169
177
|
join: (...paths) => {
|
|
170
|
-
const path = require(
|
|
178
|
+
const path = require("path");
|
|
171
179
|
return path.join(...paths);
|
|
172
180
|
},
|
|
173
181
|
resolve: (...paths) => {
|
|
174
|
-
const path = require(
|
|
182
|
+
const path = require("path");
|
|
175
183
|
return path.resolve(...paths);
|
|
176
184
|
},
|
|
177
185
|
relative: (from, to) => {
|
|
178
|
-
const path = require(
|
|
186
|
+
const path = require("path");
|
|
179
187
|
return path.relative(from, to);
|
|
180
188
|
},
|
|
181
189
|
dirname: (path) => {
|
|
182
|
-
const pathLib = require(
|
|
190
|
+
const pathLib = require("path");
|
|
183
191
|
return pathLib.dirname(path);
|
|
184
192
|
},
|
|
185
193
|
basename: (path, ext) => {
|
|
186
|
-
const pathLib = require(
|
|
194
|
+
const pathLib = require("path");
|
|
187
195
|
return pathLib.basename(path, ext);
|
|
188
|
-
}
|
|
196
|
+
},
|
|
189
197
|
},
|
|
190
|
-
grantedPermissions: [
|
|
198
|
+
grantedPermissions: ["read", "write", "execute"],
|
|
191
199
|
log: (level, message, data) => {
|
|
192
200
|
const logFn = mcpLogger[level];
|
|
193
|
-
if (typeof logFn ===
|
|
201
|
+
if (typeof logFn === "function") {
|
|
194
202
|
if (data) {
|
|
195
203
|
logFn(`${message} ${JSON.stringify(data)}`);
|
|
196
204
|
}
|
|
@@ -198,7 +206,7 @@ export class AgentEnhancedProvider {
|
|
|
198
206
|
logFn(message);
|
|
199
207
|
}
|
|
200
208
|
}
|
|
201
|
-
}
|
|
209
|
+
},
|
|
202
210
|
};
|
|
203
211
|
const toolPromise = this.mcpSystem.executeTool(toolInfo.name, args, context);
|
|
204
212
|
let result;
|
|
@@ -207,10 +215,10 @@ export class AgentEnhancedProvider {
|
|
|
207
215
|
result = await Promise.race([
|
|
208
216
|
toolPromise,
|
|
209
217
|
new Promise((_, reject) => {
|
|
210
|
-
toolAbortController.signal.addEventListener(
|
|
218
|
+
toolAbortController.signal.addEventListener("abort", () => {
|
|
211
219
|
reject(new Error(`Tool ${toolInfo.name} timed out after ${this.config.toolExecutionTimeout}`));
|
|
212
220
|
});
|
|
213
|
-
})
|
|
221
|
+
}),
|
|
214
222
|
]);
|
|
215
223
|
}
|
|
216
224
|
else {
|
|
@@ -230,7 +238,7 @@ export class AgentEnhancedProvider {
|
|
|
230
238
|
mcpLogger.error(`MCP tool ${toolInfo.name} execution failed:`, error);
|
|
231
239
|
throw error;
|
|
232
240
|
}
|
|
233
|
-
}
|
|
241
|
+
},
|
|
234
242
|
};
|
|
235
243
|
}
|
|
236
244
|
mcpLogger.info(`[AgentEnhancedProvider] Loaded ${Object.keys(mcpTools).length} MCP tools`);
|
|
@@ -246,22 +254,20 @@ export class AgentEnhancedProvider {
|
|
|
246
254
|
: optionsOrPrompt;
|
|
247
255
|
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt, schema, timeout, } = options;
|
|
248
256
|
// Get combined tools (direct + MCP) if enabled
|
|
249
|
-
const tools = this.config.enableTools
|
|
250
|
-
? await this.getCombinedTools()
|
|
251
|
-
: {};
|
|
257
|
+
const tools = this.config.enableTools ? await this.getCombinedTools() : {};
|
|
252
258
|
const log = (msg, data) => {
|
|
253
|
-
mcpLogger.info(`[AgentEnhancedProvider] ${msg}`, data ? JSON.stringify(data, null, 2) :
|
|
259
|
+
mcpLogger.info(`[AgentEnhancedProvider] ${msg}`, data ? JSON.stringify(data, null, 2) : "");
|
|
254
260
|
};
|
|
255
|
-
log(
|
|
261
|
+
log("Starting text generation", {
|
|
256
262
|
prompt: prompt.substring(0, 100),
|
|
257
263
|
toolsCount: Object.keys(tools).length,
|
|
258
|
-
maxSteps: this.config.maxSteps
|
|
264
|
+
maxSteps: this.config.maxSteps,
|
|
259
265
|
});
|
|
260
266
|
try {
|
|
261
267
|
// Parse timeout if provided
|
|
262
268
|
let abortSignal;
|
|
263
269
|
if (timeout) {
|
|
264
|
-
const timeoutMs = typeof timeout ===
|
|
270
|
+
const timeoutMs = typeof timeout === "string" ? parseTimeout(timeout) : timeout;
|
|
265
271
|
if (timeoutMs !== undefined) {
|
|
266
272
|
abortSignal = AbortSignal.timeout(timeoutMs);
|
|
267
273
|
}
|
|
@@ -279,24 +285,26 @@ export class AgentEnhancedProvider {
|
|
|
279
285
|
toolChoice: this.shouldForceToolUsage(prompt) ? "required" : "auto",
|
|
280
286
|
abortSignal, // Pass abort signal for timeout support
|
|
281
287
|
});
|
|
282
|
-
log(
|
|
288
|
+
log("Generation completed", {
|
|
283
289
|
text: result.text?.substring(0, 200),
|
|
284
290
|
finishReason: result.finishReason,
|
|
285
291
|
toolCallsCount: result.toolCalls?.length || 0,
|
|
286
292
|
toolResultsCount: result.toolResults?.length || 0,
|
|
287
|
-
stepsCount: result.steps?.length || 0
|
|
293
|
+
stepsCount: result.steps?.length || 0,
|
|
288
294
|
});
|
|
289
295
|
// Check if tools were called but no final text was generated
|
|
290
|
-
if (result.finishReason ===
|
|
291
|
-
|
|
296
|
+
if (result.finishReason === "tool-calls" &&
|
|
297
|
+
!result.text &&
|
|
298
|
+
result.toolResults?.length > 0) {
|
|
299
|
+
log("Tools called but no final text generated, creating summary response");
|
|
292
300
|
try {
|
|
293
301
|
// Extract tool results and create a summary prompt
|
|
294
|
-
let toolResultsSummary =
|
|
302
|
+
let toolResultsSummary = "";
|
|
295
303
|
if (result.toolResults) {
|
|
296
304
|
for (const toolResult of result.toolResults) {
|
|
297
305
|
const resultData = toolResult.result || toolResult;
|
|
298
306
|
// Try to extract meaningful data from the result
|
|
299
|
-
if (typeof resultData ===
|
|
307
|
+
if (typeof resultData === "object" && resultData !== null) {
|
|
300
308
|
if (resultData.success && resultData.items) {
|
|
301
309
|
// This looks like a filesystem listing
|
|
302
310
|
toolResultsSummary += `Directory listing for ${resultData.path}:\n`;
|
|
@@ -311,34 +319,36 @@ export class AgentEnhancedProvider {
|
|
|
311
319
|
else {
|
|
312
320
|
toolResultsSummary += String(resultData);
|
|
313
321
|
}
|
|
314
|
-
toolResultsSummary +=
|
|
322
|
+
toolResultsSummary += "\n\n";
|
|
315
323
|
}
|
|
316
324
|
}
|
|
317
|
-
log(
|
|
325
|
+
log("Tool results extracted", {
|
|
318
326
|
summaryLength: toolResultsSummary.length,
|
|
319
|
-
preview: toolResultsSummary.substring(0, 200)
|
|
327
|
+
preview: toolResultsSummary.substring(0, 200),
|
|
320
328
|
});
|
|
321
329
|
// Create a simple, direct summary
|
|
322
330
|
const finalText = `Based on the user request "${prompt}", here's what I found:\n\n${toolResultsSummary}`;
|
|
323
|
-
log(
|
|
331
|
+
log("Final text created", {
|
|
324
332
|
textLength: finalText.length,
|
|
325
|
-
preview: finalText.substring(0, 200)
|
|
333
|
+
preview: finalText.substring(0, 200),
|
|
326
334
|
});
|
|
327
335
|
// Return result with the formatted text
|
|
328
336
|
return {
|
|
329
337
|
...result,
|
|
330
338
|
text: finalText,
|
|
331
|
-
finishReason:
|
|
339
|
+
finishReason: "stop",
|
|
332
340
|
};
|
|
333
341
|
}
|
|
334
342
|
catch (error) {
|
|
335
|
-
log(
|
|
343
|
+
log("Error in summary generation", {
|
|
344
|
+
error: error instanceof Error ? error.message : String(error),
|
|
345
|
+
});
|
|
336
346
|
// Fallback: return raw tool results
|
|
337
347
|
const fallbackText = `Tool execution completed. Raw results: ${JSON.stringify(result.toolResults, null, 2)}`;
|
|
338
348
|
return {
|
|
339
349
|
...result,
|
|
340
350
|
text: fallbackText,
|
|
341
|
-
finishReason:
|
|
351
|
+
finishReason: "stop",
|
|
342
352
|
};
|
|
343
353
|
}
|
|
344
354
|
}
|
|
@@ -356,14 +366,12 @@ export class AgentEnhancedProvider {
|
|
|
356
366
|
: optionsOrPrompt;
|
|
357
367
|
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt, timeout, } = options;
|
|
358
368
|
// Get combined tools (direct + MCP) if enabled
|
|
359
|
-
const tools = this.config.enableTools
|
|
360
|
-
? await this.getCombinedTools()
|
|
361
|
-
: {};
|
|
369
|
+
const tools = this.config.enableTools ? await this.getCombinedTools() : {};
|
|
362
370
|
try {
|
|
363
371
|
// Parse timeout if provided
|
|
364
372
|
let abortSignal;
|
|
365
373
|
if (timeout) {
|
|
366
|
-
const timeoutMs = typeof timeout ===
|
|
374
|
+
const timeoutMs = typeof timeout === "string" ? parseTimeout(timeout) : timeout;
|
|
367
375
|
if (timeoutMs !== undefined) {
|
|
368
376
|
abortSignal = AbortSignal.timeout(timeoutMs);
|
|
369
377
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createAmazonBedrock } from "@ai-sdk/amazon-bedrock";
|
|
2
2
|
import { streamText, generateText, Output, } from "ai";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
-
import { createTimeoutController, TimeoutError, getDefaultTimeout } from "../utils/timeout.js";
|
|
4
|
+
import { createTimeoutController, TimeoutError, getDefaultTimeout, } from "../utils/timeout.js";
|
|
5
5
|
// Default system context
|
|
6
6
|
const DEFAULT_SYSTEM_CONTEXT = {
|
|
7
7
|
systemPrompt: "You are a helpful AI assistant.",
|
|
@@ -129,7 +129,7 @@ export class AmazonBedrock {
|
|
|
129
129
|
const options = typeof optionsOrPrompt === "string"
|
|
130
130
|
? { prompt: optionsOrPrompt }
|
|
131
131
|
: optionsOrPrompt;
|
|
132
|
-
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider,
|
|
132
|
+
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, "stream"), } = options;
|
|
133
133
|
// Use schema from options or fallback parameter
|
|
134
134
|
const finalSchema = schema || analysisSchema;
|
|
135
135
|
logger.debug(`[${functionTag}] Stream request started`, {
|
|
@@ -141,7 +141,7 @@ export class AmazonBedrock {
|
|
|
141
141
|
timeout,
|
|
142
142
|
});
|
|
143
143
|
// Create timeout controller if timeout is specified
|
|
144
|
-
const timeoutController = createTimeoutController(timeout, provider,
|
|
144
|
+
const timeoutController = createTimeoutController(timeout, provider, "stream");
|
|
145
145
|
const streamOptions = {
|
|
146
146
|
model: this.model,
|
|
147
147
|
prompt: prompt,
|
|
@@ -149,7 +149,9 @@ export class AmazonBedrock {
|
|
|
149
149
|
temperature,
|
|
150
150
|
maxTokens,
|
|
151
151
|
// Add abort signal if available
|
|
152
|
-
...(timeoutController && {
|
|
152
|
+
...(timeoutController && {
|
|
153
|
+
abortSignal: timeoutController.controller.signal,
|
|
154
|
+
}),
|
|
153
155
|
onError: (event) => {
|
|
154
156
|
const error = event.error;
|
|
155
157
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -234,7 +236,7 @@ export class AmazonBedrock {
|
|
|
234
236
|
const options = typeof optionsOrPrompt === "string"
|
|
235
237
|
? { prompt: optionsOrPrompt }
|
|
236
238
|
: optionsOrPrompt;
|
|
237
|
-
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider,
|
|
239
|
+
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, "generate"), } = options;
|
|
238
240
|
// Use schema from options or fallback parameter
|
|
239
241
|
const finalSchema = schema || analysisSchema;
|
|
240
242
|
logger.debug(`[${functionTag}] Generate text started`, {
|
|
@@ -247,7 +249,7 @@ export class AmazonBedrock {
|
|
|
247
249
|
timeout,
|
|
248
250
|
});
|
|
249
251
|
// Create timeout controller if timeout is specified
|
|
250
|
-
const timeoutController = createTimeoutController(timeout, provider,
|
|
252
|
+
const timeoutController = createTimeoutController(timeout, provider, "generate");
|
|
251
253
|
const generateOptions = {
|
|
252
254
|
model: this.model,
|
|
253
255
|
prompt: prompt,
|
|
@@ -255,7 +257,9 @@ export class AmazonBedrock {
|
|
|
255
257
|
temperature,
|
|
256
258
|
maxTokens,
|
|
257
259
|
// Add abort signal if available
|
|
258
|
-
...(timeoutController && {
|
|
260
|
+
...(timeoutController && {
|
|
261
|
+
abortSignal: timeoutController.controller.signal,
|
|
262
|
+
}),
|
|
259
263
|
};
|
|
260
264
|
if (finalSchema) {
|
|
261
265
|
generateOptions.experimental_output = Output.object({
|