@juspay/neurolink 2.0.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 +34 -7
- package/README.md +38 -34
- package/dist/cli/commands/config.d.ts +6 -6
- package/dist/cli/index.js +46 -35
- package/dist/core/types.d.ts +2 -0
- package/dist/lib/core/types.d.ts +2 -0
- package/dist/lib/mcp/plugins/filesystem-mcp.d.ts +1 -1
- package/dist/lib/neurolink.d.ts +2 -0
- package/dist/lib/neurolink.js +23 -2
- package/dist/lib/providers/agent-enhanced-provider.d.ts +1 -0
- package/dist/lib/providers/agent-enhanced-provider.js +115 -51
- package/dist/lib/providers/amazonBedrock.js +74 -24
- package/dist/lib/providers/anthropic.js +80 -16
- package/dist/lib/providers/azureOpenAI.js +77 -15
- package/dist/lib/providers/googleAIStudio.js +77 -26
- package/dist/lib/providers/googleVertexAI.js +77 -24
- package/dist/lib/providers/huggingFace.js +74 -26
- package/dist/lib/providers/mistralAI.js +74 -26
- package/dist/lib/providers/ollama.d.ts +1 -1
- package/dist/lib/providers/ollama.js +32 -10
- package/dist/lib/providers/openAI.js +71 -23
- package/dist/lib/providers/timeout-wrapper.d.ts +40 -0
- package/dist/lib/providers/timeout-wrapper.js +100 -0
- 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 +69 -0
- package/dist/lib/utils/timeout.js +138 -0
- package/dist/mcp/plugins/filesystem-mcp.d.ts +1 -1
- package/dist/mcp/plugins/filesystem-mcp.js +1 -1
- package/dist/neurolink.d.ts +2 -0
- package/dist/neurolink.js +23 -2
- package/dist/providers/agent-enhanced-provider.d.ts +1 -0
- package/dist/providers/agent-enhanced-provider.js +115 -51
- package/dist/providers/amazonBedrock.js +74 -24
- package/dist/providers/anthropic.js +80 -16
- package/dist/providers/azureOpenAI.js +77 -15
- package/dist/providers/googleAIStudio.js +77 -26
- package/dist/providers/googleVertexAI.js +77 -24
- package/dist/providers/huggingFace.js +74 -26
- package/dist/providers/mistralAI.js +74 -26
- package/dist/providers/ollama.d.ts +1 -1
- package/dist/providers/ollama.js +32 -10
- package/dist/providers/openAI.js +71 -23
- package/dist/providers/timeout-wrapper.d.ts +40 -0
- package/dist/providers/timeout-wrapper.js +100 -0
- package/dist/proxy/proxy-fetch.d.ts +18 -0
- package/dist/proxy/proxy-fetch.js +64 -0
- package/dist/utils/timeout.d.ts +69 -0
- package/dist/utils/timeout.js +138 -0
- package/package.json +2 -1
package/dist/providers/openAI.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { openai } from "@ai-sdk/openai";
|
|
2
2
|
import { streamText, generateText, Output, } from "ai";
|
|
3
3
|
import { logger } from "../utils/logger.js";
|
|
4
|
+
import { createTimeoutController, getDefaultTimeout, TimeoutError, } from "../utils/timeout.js";
|
|
4
5
|
// Default system context
|
|
5
6
|
const DEFAULT_SYSTEM_CONTEXT = {
|
|
6
7
|
systemPrompt: "You are a helpful AI assistant.",
|
|
@@ -59,7 +60,7 @@ export class OpenAI {
|
|
|
59
60
|
const options = typeof optionsOrPrompt === "string"
|
|
60
61
|
? { prompt: optionsOrPrompt }
|
|
61
62
|
: optionsOrPrompt;
|
|
62
|
-
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
|
|
63
|
+
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, "stream"), } = options;
|
|
63
64
|
// Use schema from options or fallback parameter
|
|
64
65
|
const finalSchema = schema || analysisSchema;
|
|
65
66
|
logger.debug(`[${functionTag}] Stream text started`, {
|
|
@@ -68,13 +69,20 @@ export class OpenAI {
|
|
|
68
69
|
promptLength: prompt.length,
|
|
69
70
|
temperature,
|
|
70
71
|
maxTokens,
|
|
72
|
+
timeout,
|
|
71
73
|
});
|
|
74
|
+
// Create timeout controller if timeout is specified
|
|
75
|
+
const timeoutController = createTimeoutController(timeout, provider, "stream");
|
|
72
76
|
const streamOptions = {
|
|
73
77
|
model: this.model,
|
|
74
78
|
prompt: prompt,
|
|
75
79
|
system: systemPrompt,
|
|
76
80
|
temperature,
|
|
77
81
|
maxTokens,
|
|
82
|
+
// Add abort signal if available
|
|
83
|
+
...(timeoutController && {
|
|
84
|
+
abortSignal: timeoutController.controller.signal,
|
|
85
|
+
}),
|
|
78
86
|
onError: (event) => {
|
|
79
87
|
const error = event.error;
|
|
80
88
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -116,15 +124,28 @@ export class OpenAI {
|
|
|
116
124
|
});
|
|
117
125
|
}
|
|
118
126
|
const result = streamText(streamOptions);
|
|
127
|
+
// For streaming, we can't clean up immediately, but the timeout will auto-clean
|
|
128
|
+
// The user should handle the stream and any timeout errors
|
|
119
129
|
return result;
|
|
120
130
|
}
|
|
121
131
|
catch (err) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
// Log timeout errors specifically
|
|
133
|
+
if (err instanceof TimeoutError) {
|
|
134
|
+
logger.debug(`[${functionTag}] Timeout error`, {
|
|
135
|
+
provider,
|
|
136
|
+
modelName: this.modelName,
|
|
137
|
+
timeout: err.timeout,
|
|
138
|
+
message: err.message,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
logger.debug(`[${functionTag}] Exception`, {
|
|
143
|
+
provider,
|
|
144
|
+
modelName: this.modelName,
|
|
145
|
+
message: "Error in streaming text",
|
|
146
|
+
err: String(err),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
128
149
|
throw err; // Re-throw error to trigger fallback
|
|
129
150
|
}
|
|
130
151
|
}
|
|
@@ -136,7 +157,7 @@ export class OpenAI {
|
|
|
136
157
|
const options = typeof optionsOrPrompt === "string"
|
|
137
158
|
? { prompt: optionsOrPrompt }
|
|
138
159
|
: optionsOrPrompt;
|
|
139
|
-
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, } = options;
|
|
160
|
+
const { prompt, temperature = 0.7, maxTokens = 1000, systemPrompt = DEFAULT_SYSTEM_CONTEXT.systemPrompt, schema, timeout = getDefaultTimeout(provider, "generate"), } = options;
|
|
140
161
|
// Use schema from options or fallback parameter
|
|
141
162
|
const finalSchema = schema || analysisSchema;
|
|
142
163
|
logger.debug(`[${functionTag}] Generate text started`, {
|
|
@@ -145,36 +166,63 @@ export class OpenAI {
|
|
|
145
166
|
promptLength: prompt.length,
|
|
146
167
|
temperature,
|
|
147
168
|
maxTokens,
|
|
169
|
+
timeout,
|
|
148
170
|
});
|
|
171
|
+
// Create timeout controller if timeout is specified
|
|
172
|
+
const timeoutController = createTimeoutController(timeout, provider, "generate");
|
|
149
173
|
const generateOptions = {
|
|
150
174
|
model: this.model,
|
|
151
175
|
prompt: prompt,
|
|
152
176
|
system: systemPrompt,
|
|
153
177
|
temperature,
|
|
154
178
|
maxTokens,
|
|
179
|
+
// Add abort signal if available
|
|
180
|
+
...(timeoutController && {
|
|
181
|
+
abortSignal: timeoutController.controller.signal,
|
|
182
|
+
}),
|
|
155
183
|
};
|
|
156
184
|
if (finalSchema) {
|
|
157
185
|
generateOptions.experimental_output = Output.object({
|
|
158
186
|
schema: finalSchema,
|
|
159
187
|
});
|
|
160
188
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
189
|
+
try {
|
|
190
|
+
const result = await generateText(generateOptions);
|
|
191
|
+
// Clean up timeout if successful
|
|
192
|
+
timeoutController?.cleanup();
|
|
193
|
+
logger.debug(`[${functionTag}] Generate text completed`, {
|
|
194
|
+
provider,
|
|
195
|
+
modelName: this.modelName,
|
|
196
|
+
usage: result.usage,
|
|
197
|
+
finishReason: result.finishReason,
|
|
198
|
+
responseLength: result.text?.length || 0,
|
|
199
|
+
timeout,
|
|
200
|
+
});
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
finally {
|
|
204
|
+
// Always cleanup timeout
|
|
205
|
+
timeoutController?.cleanup();
|
|
206
|
+
}
|
|
170
207
|
}
|
|
171
208
|
catch (err) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
209
|
+
// Log timeout errors specifically
|
|
210
|
+
if (err instanceof TimeoutError) {
|
|
211
|
+
logger.debug(`[${functionTag}] Timeout error`, {
|
|
212
|
+
provider,
|
|
213
|
+
modelName: this.modelName,
|
|
214
|
+
timeout: err.timeout,
|
|
215
|
+
message: err.message,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
logger.debug(`[${functionTag}] Exception`, {
|
|
220
|
+
provider,
|
|
221
|
+
modelName: this.modelName,
|
|
222
|
+
message: "Error in generating text",
|
|
223
|
+
err: String(err),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
178
226
|
throw err; // Re-throw error to trigger fallback
|
|
179
227
|
}
|
|
180
228
|
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeout wrapper for AI provider operations
|
|
3
|
+
*
|
|
4
|
+
* Provides a consistent way to add timeout functionality to any async operation.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Wrap an async operation with a timeout
|
|
8
|
+
* @param promise - The promise to wrap
|
|
9
|
+
* @param timeout - Timeout duration (number in ms or string with unit)
|
|
10
|
+
* @param provider - Provider name for error messages
|
|
11
|
+
* @param operation - Operation type (generate or stream)
|
|
12
|
+
* @returns The result of the promise or throws TimeoutError
|
|
13
|
+
*/
|
|
14
|
+
export declare function withTimeout<T>(promise: Promise<T>, timeout: number | string | undefined, provider: string, operation: "generate" | "stream"): Promise<T>;
|
|
15
|
+
/**
|
|
16
|
+
* Wrap a streaming async generator with timeout
|
|
17
|
+
* @param generator - The async generator to wrap
|
|
18
|
+
* @param timeout - Timeout duration for the entire stream
|
|
19
|
+
* @param provider - Provider name for error messages
|
|
20
|
+
* @returns Wrapped async generator that respects timeout
|
|
21
|
+
*/
|
|
22
|
+
export declare function withStreamingTimeout<T>(generator: AsyncGenerator<T>, timeout: number | string | undefined, provider: string): AsyncGenerator<T>;
|
|
23
|
+
/**
|
|
24
|
+
* Create an abort controller with timeout
|
|
25
|
+
* @param timeout - Timeout duration
|
|
26
|
+
* @param provider - Provider name for error messages
|
|
27
|
+
* @param operation - Operation type
|
|
28
|
+
* @returns AbortController and cleanup function
|
|
29
|
+
*/
|
|
30
|
+
export declare function createTimeoutController(timeout: number | string | undefined, provider: string, operation: "generate" | "stream"): {
|
|
31
|
+
controller: AbortController;
|
|
32
|
+
cleanup: () => void;
|
|
33
|
+
timeoutMs: number;
|
|
34
|
+
} | null;
|
|
35
|
+
/**
|
|
36
|
+
* Merge abort signals (for combining user abort with timeout)
|
|
37
|
+
* @param signals - Array of abort signals to merge
|
|
38
|
+
* @returns Combined abort controller
|
|
39
|
+
*/
|
|
40
|
+
export declare function mergeAbortSignals(signals: (AbortSignal | undefined)[]): AbortController;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeout wrapper for AI provider operations
|
|
3
|
+
*
|
|
4
|
+
* Provides a consistent way to add timeout functionality to any async operation.
|
|
5
|
+
*/
|
|
6
|
+
import { parseTimeout, TimeoutError, createTimeoutPromise, } from "../utils/timeout.js";
|
|
7
|
+
/**
|
|
8
|
+
* Wrap an async operation with a timeout
|
|
9
|
+
* @param promise - The promise to wrap
|
|
10
|
+
* @param timeout - Timeout duration (number in ms or string with unit)
|
|
11
|
+
* @param provider - Provider name for error messages
|
|
12
|
+
* @param operation - Operation type (generate or stream)
|
|
13
|
+
* @returns The result of the promise or throws TimeoutError
|
|
14
|
+
*/
|
|
15
|
+
export async function withTimeout(promise, timeout, provider, operation) {
|
|
16
|
+
const timeoutPromise = createTimeoutPromise(timeout, provider, operation);
|
|
17
|
+
if (!timeoutPromise) {
|
|
18
|
+
// No timeout specified, return original promise
|
|
19
|
+
return promise;
|
|
20
|
+
}
|
|
21
|
+
// Race between the actual operation and timeout
|
|
22
|
+
return Promise.race([promise, timeoutPromise]);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Wrap a streaming async generator with timeout
|
|
26
|
+
* @param generator - The async generator to wrap
|
|
27
|
+
* @param timeout - Timeout duration for the entire stream
|
|
28
|
+
* @param provider - Provider name for error messages
|
|
29
|
+
* @returns Wrapped async generator that respects timeout
|
|
30
|
+
*/
|
|
31
|
+
export async function* withStreamingTimeout(generator, timeout, provider) {
|
|
32
|
+
const timeoutMs = parseTimeout(timeout);
|
|
33
|
+
if (!timeoutMs) {
|
|
34
|
+
// No timeout, pass through original generator
|
|
35
|
+
yield* generator;
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const startTime = Date.now();
|
|
39
|
+
try {
|
|
40
|
+
for await (const chunk of generator) {
|
|
41
|
+
// Check if we've exceeded the timeout
|
|
42
|
+
if (Date.now() - startTime > timeoutMs) {
|
|
43
|
+
throw new TimeoutError(`${provider} streaming operation timed out after ${timeout}`, timeoutMs, provider, "stream");
|
|
44
|
+
}
|
|
45
|
+
yield chunk;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
// Ensure generator is properly closed
|
|
50
|
+
if (generator.return) {
|
|
51
|
+
await generator.return(undefined);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Create an abort controller with timeout
|
|
57
|
+
* @param timeout - Timeout duration
|
|
58
|
+
* @param provider - Provider name for error messages
|
|
59
|
+
* @param operation - Operation type
|
|
60
|
+
* @returns AbortController and cleanup function
|
|
61
|
+
*/
|
|
62
|
+
export function createTimeoutController(timeout, provider, operation) {
|
|
63
|
+
const timeoutMs = parseTimeout(timeout);
|
|
64
|
+
if (!timeoutMs) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const controller = new AbortController();
|
|
68
|
+
const timer = setTimeout(() => {
|
|
69
|
+
controller.abort(new TimeoutError(`${provider} ${operation} operation timed out after ${timeout}`, timeoutMs, provider, operation));
|
|
70
|
+
}, timeoutMs);
|
|
71
|
+
// Cleanup function to clear the timer
|
|
72
|
+
const cleanup = () => {
|
|
73
|
+
clearTimeout(timer);
|
|
74
|
+
};
|
|
75
|
+
return { controller, cleanup, timeoutMs };
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Merge abort signals (for combining user abort with timeout)
|
|
79
|
+
* @param signals - Array of abort signals to merge
|
|
80
|
+
* @returns Combined abort controller
|
|
81
|
+
*/
|
|
82
|
+
export function mergeAbortSignals(signals) {
|
|
83
|
+
const controller = new AbortController();
|
|
84
|
+
// Listen to all signals and abort when any fires
|
|
85
|
+
for (const signal of signals) {
|
|
86
|
+
if (signal && !signal.aborted) {
|
|
87
|
+
signal.addEventListener("abort", () => {
|
|
88
|
+
if (!controller.signal.aborted) {
|
|
89
|
+
controller.abort(signal.reason);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// If any signal is already aborted, abort immediately
|
|
94
|
+
if (signal?.aborted) {
|
|
95
|
+
controller.abort(signal.reason);
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return controller;
|
|
100
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
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 declare function createProxyFetch(): typeof fetch;
|
|
10
|
+
/**
|
|
11
|
+
* Get proxy status information
|
|
12
|
+
*/
|
|
13
|
+
export declare function getProxyStatus(): {
|
|
14
|
+
enabled: boolean;
|
|
15
|
+
httpProxy: string | null;
|
|
16
|
+
httpsProxy: string | null;
|
|
17
|
+
method: string;
|
|
18
|
+
};
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeout utilities for NeuroLink
|
|
3
|
+
*
|
|
4
|
+
* Provides flexible timeout parsing and error handling for AI operations.
|
|
5
|
+
* Supports multiple time formats: milliseconds, seconds, minutes, hours.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Custom error class for timeout operations
|
|
9
|
+
*/
|
|
10
|
+
export declare class TimeoutError extends Error {
|
|
11
|
+
readonly timeout: number;
|
|
12
|
+
readonly provider?: string | undefined;
|
|
13
|
+
readonly operation?: "generate" | "stream" | undefined;
|
|
14
|
+
constructor(message: string, timeout: number, provider?: string | undefined, operation?: "generate" | "stream" | undefined);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse timeout value from various formats
|
|
18
|
+
* @param timeout - Can be number (ms), string with unit, or undefined
|
|
19
|
+
* @returns Parsed timeout in milliseconds or undefined
|
|
20
|
+
* @throws Error if format is invalid
|
|
21
|
+
*
|
|
22
|
+
* Examples:
|
|
23
|
+
* - parseTimeout(5000) => 5000
|
|
24
|
+
* - parseTimeout('30s') => 30000
|
|
25
|
+
* - parseTimeout('2m') => 120000
|
|
26
|
+
* - parseTimeout('1.5h') => 5400000
|
|
27
|
+
* - parseTimeout(undefined) => undefined
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseTimeout(timeout: number | string | undefined): number | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Default timeout configurations for different providers and operations
|
|
32
|
+
*/
|
|
33
|
+
export declare const DEFAULT_TIMEOUTS: {
|
|
34
|
+
global: string;
|
|
35
|
+
streaming: string;
|
|
36
|
+
providers: {
|
|
37
|
+
openai: string;
|
|
38
|
+
bedrock: string;
|
|
39
|
+
vertex: string;
|
|
40
|
+
anthropic: string;
|
|
41
|
+
azure: string;
|
|
42
|
+
"google-ai": string;
|
|
43
|
+
huggingface: string;
|
|
44
|
+
ollama: string;
|
|
45
|
+
mistral: string;
|
|
46
|
+
};
|
|
47
|
+
tools: {
|
|
48
|
+
default: string;
|
|
49
|
+
filesystem: string;
|
|
50
|
+
network: string;
|
|
51
|
+
computation: string;
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Get default timeout for a specific provider
|
|
56
|
+
* @param provider - Provider name
|
|
57
|
+
* @param operation - Operation type (generate or stream)
|
|
58
|
+
* @returns Default timeout string
|
|
59
|
+
*/
|
|
60
|
+
export declare function getDefaultTimeout(provider: string, operation?: "generate" | "stream"): string;
|
|
61
|
+
/**
|
|
62
|
+
* Create a timeout promise that rejects after specified duration
|
|
63
|
+
* @param timeout - Timeout duration
|
|
64
|
+
* @param provider - Provider name for error message
|
|
65
|
+
* @param operation - Operation type for error message
|
|
66
|
+
* @returns Promise that rejects with TimeoutError
|
|
67
|
+
*/
|
|
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";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeout utilities for NeuroLink
|
|
3
|
+
*
|
|
4
|
+
* Provides flexible timeout parsing and error handling for AI operations.
|
|
5
|
+
* Supports multiple time formats: milliseconds, seconds, minutes, hours.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Custom error class for timeout operations
|
|
9
|
+
*/
|
|
10
|
+
export class TimeoutError extends Error {
|
|
11
|
+
timeout;
|
|
12
|
+
provider;
|
|
13
|
+
operation;
|
|
14
|
+
constructor(message, timeout, provider, operation) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.timeout = timeout;
|
|
17
|
+
this.provider = provider;
|
|
18
|
+
this.operation = operation;
|
|
19
|
+
this.name = "TimeoutError";
|
|
20
|
+
// Maintains proper stack trace for where error was thrown
|
|
21
|
+
if (typeof Error.captureStackTrace === "function") {
|
|
22
|
+
Error.captureStackTrace(this, TimeoutError);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Parse timeout value from various formats
|
|
28
|
+
* @param timeout - Can be number (ms), string with unit, or undefined
|
|
29
|
+
* @returns Parsed timeout in milliseconds or undefined
|
|
30
|
+
* @throws Error if format is invalid
|
|
31
|
+
*
|
|
32
|
+
* Examples:
|
|
33
|
+
* - parseTimeout(5000) => 5000
|
|
34
|
+
* - parseTimeout('30s') => 30000
|
|
35
|
+
* - parseTimeout('2m') => 120000
|
|
36
|
+
* - parseTimeout('1.5h') => 5400000
|
|
37
|
+
* - parseTimeout(undefined) => undefined
|
|
38
|
+
*/
|
|
39
|
+
export function parseTimeout(timeout) {
|
|
40
|
+
if (timeout === undefined) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
if (typeof timeout === "number") {
|
|
44
|
+
if (timeout <= 0) {
|
|
45
|
+
throw new Error(`Timeout must be positive, got: ${timeout}`);
|
|
46
|
+
}
|
|
47
|
+
return timeout; // Assume milliseconds
|
|
48
|
+
}
|
|
49
|
+
if (typeof timeout === "string") {
|
|
50
|
+
// Match number (including decimals) followed by optional unit
|
|
51
|
+
const match = timeout.match(/^(\d+(?:\.\d+)?)(ms|s|m|h)?$/);
|
|
52
|
+
if (!match) {
|
|
53
|
+
throw new Error(`Invalid timeout format: ${timeout}. Use formats like '30s', '2m', '500ms', or '1.5h'`);
|
|
54
|
+
}
|
|
55
|
+
const value = parseFloat(match[1]);
|
|
56
|
+
if (value <= 0) {
|
|
57
|
+
throw new Error(`Timeout must be positive, got: ${value}`);
|
|
58
|
+
}
|
|
59
|
+
const unit = match[2] || "ms";
|
|
60
|
+
switch (unit) {
|
|
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
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
throw new Error(`Invalid timeout type: ${typeof timeout}`);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Default timeout configurations for different providers and operations
|
|
77
|
+
*/
|
|
78
|
+
export const DEFAULT_TIMEOUTS = {
|
|
79
|
+
global: "30s", // Default for all providers
|
|
80
|
+
streaming: "2m", // Longer timeout for streaming operations
|
|
81
|
+
providers: {
|
|
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
|
|
91
|
+
},
|
|
92
|
+
tools: {
|
|
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
|
+
},
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Get default timeout for a specific provider
|
|
101
|
+
* @param provider - Provider name
|
|
102
|
+
* @param operation - Operation type (generate or stream)
|
|
103
|
+
* @returns Default timeout string
|
|
104
|
+
*/
|
|
105
|
+
export function getDefaultTimeout(provider, operation = "generate") {
|
|
106
|
+
if (operation === "stream") {
|
|
107
|
+
return DEFAULT_TIMEOUTS.streaming;
|
|
108
|
+
}
|
|
109
|
+
const providerKey = provider.toLowerCase().replace("_", "-");
|
|
110
|
+
return (DEFAULT_TIMEOUTS.providers[providerKey] || DEFAULT_TIMEOUTS.global);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Create a timeout promise that rejects after specified duration
|
|
114
|
+
* @param timeout - Timeout duration
|
|
115
|
+
* @param provider - Provider name for error message
|
|
116
|
+
* @param operation - Operation type for error message
|
|
117
|
+
* @returns Promise that rejects with TimeoutError
|
|
118
|
+
*/
|
|
119
|
+
export function createTimeoutPromise(timeout, provider, operation) {
|
|
120
|
+
const timeoutMs = parseTimeout(timeout);
|
|
121
|
+
if (!timeoutMs) {
|
|
122
|
+
return null; // No timeout
|
|
123
|
+
}
|
|
124
|
+
return new Promise((_, reject) => {
|
|
125
|
+
const timer = setTimeout(() => {
|
|
126
|
+
reject(new TimeoutError(`${provider} ${operation} operation timed out after ${timeout}`, timeoutMs, provider, operation));
|
|
127
|
+
}, timeoutMs);
|
|
128
|
+
// Unref the timer so it doesn't keep the process alive (Node.js only)
|
|
129
|
+
if (typeof timer === "object" &&
|
|
130
|
+
timer &&
|
|
131
|
+
"unref" in timer &&
|
|
132
|
+
typeof timer.unref === "function") {
|
|
133
|
+
timer.unref();
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
// Re-export createTimeoutController from timeout-wrapper for convenience
|
|
138
|
+
export { createTimeoutController } from "../providers/timeout-wrapper.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.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",
|
|
@@ -138,6 +138,7 @@
|
|
|
138
138
|
"dotenv": "^16.5.0",
|
|
139
139
|
"express": "^5.1.0",
|
|
140
140
|
"inquirer": "^9.2.15",
|
|
141
|
+
"undici": "^6.6.2",
|
|
141
142
|
"ora": "^7.0.1",
|
|
142
143
|
"playwright": "^1.52.0",
|
|
143
144
|
"uuid": "^11.1.0",
|