@juspay/neurolink 12.51.0 → 12.51.1
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 +3 -3
- package/dist/browser/neurolink.min.js +406 -406
- package/dist/constants/timeouts.d.ts +6 -0
- package/dist/constants/timeouts.js +6 -0
- package/dist/utils/errorHandling.d.ts +11 -1
- package/dist/utils/errorHandling.js +17 -2
- package/dist/workflow/core/ensembleExecutor.js +29 -16
- package/package.json +2 -1
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
* @author NeuroLink Team
|
|
9
9
|
* @version 1.0.0
|
|
10
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* Largest delay `setTimeout` honours (2^31 - 1 ms, about 24.8 days). A longer
|
|
13
|
+
* delay is not "later": Node warns and fires after 1 ms, so a caller-supplied
|
|
14
|
+
* deadline above this must be held at it rather than handed to the timer.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_TIMER_MS = 2147483647;
|
|
11
17
|
/**
|
|
12
18
|
* Tool execution timeout constants
|
|
13
19
|
* These values balance reliability vs performance for AI tool operations
|
|
@@ -8,6 +8,12 @@
|
|
|
8
8
|
* @author NeuroLink Team
|
|
9
9
|
* @version 1.0.0
|
|
10
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* Largest delay `setTimeout` honours (2^31 - 1 ms, about 24.8 days). A longer
|
|
13
|
+
* delay is not "later": Node warns and fires after 1 ms, so a caller-supplied
|
|
14
|
+
* deadline above this must be held at it rather than handed to the timer.
|
|
15
|
+
*/
|
|
16
|
+
export const MAX_TIMER_MS = 2_147_483_647;
|
|
11
17
|
/**
|
|
12
18
|
* Tool execution timeout constants
|
|
13
19
|
* These values balance reliability vs performance for AI tool operations
|
|
@@ -361,7 +361,17 @@ export declare class ErrorFactory {
|
|
|
361
361
|
static csvProcessingFailed(filename: string, originalError: Error): NeuroLinkError;
|
|
362
362
|
}
|
|
363
363
|
/**
|
|
364
|
-
* Timeout wrapper for async operations
|
|
364
|
+
* Timeout wrapper for async operations.
|
|
365
|
+
*
|
|
366
|
+
* Races an already-created promise against a deadline. It cannot cancel that
|
|
367
|
+
* promise: when the deadline wins the operation keeps running as an abandoned
|
|
368
|
+
* ghost. A caller that owns the abortable operation (an HTTP request, a
|
|
369
|
+
* provider call) must hand it an `AbortSignal` itself and abort it when this
|
|
370
|
+
* rejects.
|
|
371
|
+
*
|
|
372
|
+
* `timeoutMs` is held at `MAX_TIMER_MS`: a longer deadline would otherwise be
|
|
373
|
+
* handed to `setTimeout`, which fires after 1 ms and so rejected an operation
|
|
374
|
+
* that had asked for the longest wait available.
|
|
365
375
|
*/
|
|
366
376
|
export declare function withTimeout<T>(promise: Promise<T>, timeoutMs: number, timeoutError?: Error): Promise<T>;
|
|
367
377
|
/**
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Provides structured error management for tool execution and system operations
|
|
4
4
|
*/
|
|
5
5
|
import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
|
|
6
|
+
import { MAX_TIMER_MS } from "../constants/timeouts.js";
|
|
6
7
|
import { logger } from "./logger.js";
|
|
7
8
|
import { CircuitBreakerOpenError } from "../types/index.js";
|
|
8
9
|
import { HITLTimeoutError } from "../hitl/hitlErrors.js";
|
|
@@ -1081,14 +1082,28 @@ export class ErrorFactory {
|
|
|
1081
1082
|
}
|
|
1082
1083
|
}
|
|
1083
1084
|
/**
|
|
1084
|
-
* Timeout wrapper for async operations
|
|
1085
|
+
* Timeout wrapper for async operations.
|
|
1086
|
+
*
|
|
1087
|
+
* Races an already-created promise against a deadline. It cannot cancel that
|
|
1088
|
+
* promise: when the deadline wins the operation keeps running as an abandoned
|
|
1089
|
+
* ghost. A caller that owns the abortable operation (an HTTP request, a
|
|
1090
|
+
* provider call) must hand it an `AbortSignal` itself and abort it when this
|
|
1091
|
+
* rejects.
|
|
1092
|
+
*
|
|
1093
|
+
* `timeoutMs` is held at `MAX_TIMER_MS`: a longer deadline would otherwise be
|
|
1094
|
+
* handed to `setTimeout`, which fires after 1 ms and so rejected an operation
|
|
1095
|
+
* that had asked for the longest wait available.
|
|
1085
1096
|
*/
|
|
1086
1097
|
export async function withTimeout(promise, timeoutMs, timeoutError) {
|
|
1087
1098
|
let timer;
|
|
1099
|
+
// An explicit upper-bound comparison, and `>` rather than `<=`: NaN fails
|
|
1100
|
+
// `>`, so NaN, zero and negative deadlines reach `setTimeout` as they always
|
|
1101
|
+
// did, and only a value above the limit is replaced by it.
|
|
1102
|
+
const delayMs = timeoutMs > MAX_TIMER_MS ? MAX_TIMER_MS : timeoutMs;
|
|
1088
1103
|
const timeoutPromise = new Promise((_, reject) => {
|
|
1089
1104
|
timer = setTimeout(() => {
|
|
1090
1105
|
reject(timeoutError || new Error(`Operation timed out after ${timeoutMs}ms`));
|
|
1091
|
-
},
|
|
1106
|
+
}, delayMs);
|
|
1092
1107
|
});
|
|
1093
1108
|
try {
|
|
1094
1109
|
return await Promise.race([promise, timeoutPromise]);
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Parallel execution engine for ensemble workflows
|
|
4
4
|
*/
|
|
5
5
|
import pLimit from "p-limit";
|
|
6
|
+
import { MAX_TIMER_MS } from "../../constants/timeouts.js";
|
|
6
7
|
import { AIProviderFactory } from "../../core/factory.js";
|
|
7
8
|
import { logger } from "../../utils/logger.js";
|
|
8
9
|
import { SpanSerializer, SpanType, SpanStatus, getMetricsAggregator, } from "../../observability/index.js";
|
|
@@ -130,12 +131,13 @@ async function executeModel(options, workflowDefaultSystemPrompt) {
|
|
|
130
131
|
const MAX_ATTEMPTS = 2;
|
|
131
132
|
while (true) {
|
|
132
133
|
attempts++;
|
|
133
|
-
result = await executeWithTimeout(async () => {
|
|
134
|
+
result = await executeWithTimeout(async (abortSignal) => {
|
|
134
135
|
return await provider.generate({
|
|
135
136
|
prompt,
|
|
136
137
|
systemPrompt: resolvedSystemPrompt,
|
|
137
138
|
temperature: model.temperature,
|
|
138
139
|
maxTokens: model.maxTokens,
|
|
140
|
+
abortSignal,
|
|
139
141
|
});
|
|
140
142
|
}, timeout, `Model ${model.provider}/${model.model} timed out after ${timeout}ms`);
|
|
141
143
|
const contentLen = result?.content?.length ?? 0;
|
|
@@ -199,14 +201,29 @@ async function createProvider(model) {
|
|
|
199
201
|
return await AIProviderFactory.createProvider(model.provider, model.model);
|
|
200
202
|
}
|
|
201
203
|
/**
|
|
202
|
-
*
|
|
203
|
-
*
|
|
204
|
+
* Run an abortable operation under a deadline.
|
|
205
|
+
*
|
|
206
|
+
* The operation receives the signal of an `AbortController` that this function
|
|
207
|
+
* aborts the moment the deadline lapses, so the owner of the work (the provider
|
|
208
|
+
* call and its HTTP request) is cancelled rather than abandoned. `Promise.race`
|
|
209
|
+
* alone only stops this caller waiting; it cannot stop a promise that already
|
|
210
|
+
* exists, so cancelling is the operation's job once it is handed the signal.
|
|
211
|
+
*
|
|
212
|
+
* `timeoutMs` is held at `MAX_TIMER_MS`: `setTimeout` fires after 1 ms for a
|
|
213
|
+
* longer delay, which turned the longest deadline a workflow could ask for into
|
|
214
|
+
* an immediate failure.
|
|
215
|
+
* @param run - Operation to execute; observes the signal to stop early
|
|
204
216
|
* @param timeoutMs - Timeout in milliseconds
|
|
205
217
|
* @param timeoutMessage - Error message for timeout
|
|
206
|
-
* @returns Result of
|
|
218
|
+
* @returns Result of the operation
|
|
207
219
|
*/
|
|
208
|
-
async function executeWithTimeout(
|
|
220
|
+
async function executeWithTimeout(run, timeoutMs, timeoutMessage) {
|
|
221
|
+
const controller = new AbortController();
|
|
209
222
|
let timeoutHandle;
|
|
223
|
+
// An explicit upper-bound comparison, and `>` rather than `<=`: NaN fails
|
|
224
|
+
// `>`, so NaN, zero and negative deadlines reach `setTimeout` as they always
|
|
225
|
+
// did, and only a value above the limit is replaced by it.
|
|
226
|
+
const delayMs = timeoutMs > MAX_TIMER_MS ? MAX_TIMER_MS : timeoutMs;
|
|
210
227
|
const timeoutPromise = new Promise((_, reject) => {
|
|
211
228
|
timeoutHandle = setTimeout(() => {
|
|
212
229
|
const error = new WorkflowError(timeoutMessage, {
|
|
@@ -215,21 +232,17 @@ async function executeWithTimeout(fn, timeoutMs, timeoutMessage) {
|
|
|
215
232
|
phase: "ensemble",
|
|
216
233
|
retryable: true,
|
|
217
234
|
});
|
|
235
|
+
// Reject before aborting: the abort can make the operation's own
|
|
236
|
+
// promise fail, and the race must already hold the deadline error.
|
|
218
237
|
reject(error);
|
|
219
|
-
|
|
238
|
+
controller.abort(error);
|
|
239
|
+
}, delayMs);
|
|
220
240
|
});
|
|
221
241
|
try {
|
|
222
|
-
|
|
223
|
-
if (timeoutHandle) {
|
|
224
|
-
clearTimeout(timeoutHandle);
|
|
225
|
-
}
|
|
226
|
-
return result;
|
|
242
|
+
return await Promise.race([run(controller.signal), timeoutPromise]);
|
|
227
243
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
clearTimeout(timeoutHandle);
|
|
231
|
-
}
|
|
232
|
-
throw error;
|
|
244
|
+
finally {
|
|
245
|
+
clearTimeout(timeoutHandle);
|
|
233
246
|
}
|
|
234
247
|
}
|
|
235
248
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "12.51.
|
|
3
|
+
"version": "12.51.1",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|
|
@@ -199,6 +199,7 @@
|
|
|
199
199
|
"test:bugfixes": "pnpm exec tsx test/continuous-test-suite-bugfixes.ts",
|
|
200
200
|
"test:json-e2e": "pnpm exec tsx test/continuous-test-suite-json-e2e.ts",
|
|
201
201
|
"test:workflow": "pnpm exec tsx test/continuous-test-suite-workflow.ts",
|
|
202
|
+
"test:workflow-deadlines": "pnpm exec tsx test/continuous-test-suite-workflow-deadlines.ts",
|
|
202
203
|
"test:hitl": "pnpm exec tsx test/continuous-test-suite-hitl.ts",
|
|
203
204
|
"test:hitl:timeout-exclusions": "pnpm exec tsx test/continuous-test-suite-hitl-timeout-exclusions.ts",
|
|
204
205
|
"test:tasks": "pnpm exec tsx test/continuous-test-suite-tasks.ts",
|