@juspay/neurolink 10.8.22 → 10.9.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 +12 -0
- package/dist/agent/directTools.d.ts +65 -0
- package/dist/agent/directTools.js +86 -50
- package/dist/browser/neurolink.min.js +390 -390
- package/dist/cli/commands/proxy.js +51 -20
- package/dist/lib/agent/directTools.d.ts +65 -0
- package/dist/lib/agent/directTools.js +86 -50
- package/dist/lib/proxy/proxyLifecycle.d.ts +5 -0
- package/dist/lib/proxy/proxyLifecycle.js +61 -11
- package/dist/lib/proxy/usageStats.d.ts +2 -0
- package/dist/lib/proxy/usageStats.js +4 -0
- package/dist/lib/types/proxy.d.ts +7 -0
- package/dist/proxy/proxyLifecycle.d.ts +5 -0
- package/dist/proxy/proxyLifecycle.js +61 -11
- package/dist/proxy/usageStats.d.ts +2 -0
- package/dist/proxy/usageStats.js +4 -0
- package/dist/types/proxy.d.ts +7 -0
- package/package.json +3 -2
|
@@ -9,6 +9,8 @@ const SCHEMA_VERSION = 1;
|
|
|
9
9
|
const DEFAULT_QUEUE_CAPACITY = 10_000;
|
|
10
10
|
const DEFAULT_BATCH_SIZE = 256;
|
|
11
11
|
const DEFAULT_FLUSH_INTERVAL_MS = 25;
|
|
12
|
+
const DEFAULT_MAX_WRITE_RETRIES = 3;
|
|
13
|
+
const MAX_WRITE_RETRY_DELAY_MS = 1_000;
|
|
12
14
|
const LIFECYCLE_APPEND_TIMEOUT_MS = 2_000;
|
|
13
15
|
const MAX_SHORT_FIELD_LENGTH = 256;
|
|
14
16
|
const SESSION_KEY_FILE = ".proxy-lifecycle-session-key";
|
|
@@ -17,6 +19,7 @@ let lifecycleLogDir;
|
|
|
17
19
|
let queueCapacity = DEFAULT_QUEUE_CAPACITY;
|
|
18
20
|
let batchSize = DEFAULT_BATCH_SIZE;
|
|
19
21
|
let flushIntervalMs = DEFAULT_FLUSH_INTERVAL_MS;
|
|
22
|
+
let maxWriteRetries = DEFAULT_MAX_WRITE_RETRIES;
|
|
20
23
|
let processInstanceId = randomUUID();
|
|
21
24
|
let sessionHashKey = randomBytes(32);
|
|
22
25
|
let nextSequence = 1;
|
|
@@ -28,10 +31,13 @@ let queueDrops = 0;
|
|
|
28
31
|
let invalidDrops = 0;
|
|
29
32
|
let writeDrops = 0;
|
|
30
33
|
let writeFailures = 0;
|
|
34
|
+
let writeRetries = 0;
|
|
31
35
|
let inFlight = 0;
|
|
32
36
|
let queue = [];
|
|
33
37
|
let flushTimer;
|
|
34
38
|
let flushInFlight;
|
|
39
|
+
let nextFlushDelayMs;
|
|
40
|
+
let appendLifecycleFile = appendFile;
|
|
35
41
|
function positiveInteger(value, fallback) {
|
|
36
42
|
return Number.isInteger(value) && (value ?? 0) > 0
|
|
37
43
|
? value
|
|
@@ -123,14 +129,14 @@ function clearScheduledFlush() {
|
|
|
123
129
|
flushTimer = undefined;
|
|
124
130
|
}
|
|
125
131
|
}
|
|
126
|
-
function scheduleFlush() {
|
|
132
|
+
function scheduleFlush(delayMs = flushIntervalMs) {
|
|
127
133
|
if (flushTimer || flushInFlight || queue.length === 0) {
|
|
128
134
|
return;
|
|
129
135
|
}
|
|
130
136
|
flushTimer = setTimeout(() => {
|
|
131
137
|
flushTimer = undefined;
|
|
132
138
|
void startFlush();
|
|
133
|
-
},
|
|
139
|
+
}, delayMs);
|
|
134
140
|
flushTimer.unref?.();
|
|
135
141
|
}
|
|
136
142
|
async function flushBatch() {
|
|
@@ -143,27 +149,53 @@ async function flushBatch() {
|
|
|
143
149
|
const byPath = new Map();
|
|
144
150
|
for (const item of batch) {
|
|
145
151
|
const path = join(item.logDir, `proxy-lifecycle-${item.date}.jsonl`);
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
byPath.set(path,
|
|
152
|
+
const items = byPath.get(path) ?? [];
|
|
153
|
+
items.push(item);
|
|
154
|
+
byPath.set(path, items);
|
|
149
155
|
}
|
|
150
|
-
|
|
156
|
+
const retries = [];
|
|
157
|
+
let retryDelayMs = 0;
|
|
158
|
+
for (const [path, items] of byPath) {
|
|
159
|
+
const lines = items.map((item) => `${JSON.stringify(item.record)}\n`);
|
|
151
160
|
try {
|
|
152
161
|
// This best-effort telemetry sink intentionally avoids fsync so request
|
|
153
162
|
// throughput is not coupled to storage latency. Loss is surfaced by
|
|
154
163
|
// writeDrops/writeFailures rather than delaying proxy responses.
|
|
155
|
-
await withTimeout(
|
|
164
|
+
await withTimeout(appendLifecycleFile(path, lines.join(""), { mode: 0o600 }), LIFECYCLE_APPEND_TIMEOUT_MS, "Timed out writing proxy lifecycle metadata");
|
|
156
165
|
written += lines.length;
|
|
157
166
|
}
|
|
158
167
|
catch (error) {
|
|
159
|
-
dropped += lines.length;
|
|
160
|
-
writeDrops += lines.length;
|
|
161
168
|
writeFailures += 1;
|
|
169
|
+
const retryable = items.filter((item) => item.writeRetries < maxWriteRetries);
|
|
170
|
+
const exhausted = items.length - retryable.length;
|
|
171
|
+
if (retryable.length > 0) {
|
|
172
|
+
const nextRetries = retryable.map((item) => ({
|
|
173
|
+
...item,
|
|
174
|
+
writeRetries: item.writeRetries + 1,
|
|
175
|
+
}));
|
|
176
|
+
retries.push(...nextRetries);
|
|
177
|
+
writeRetries += nextRetries.length;
|
|
178
|
+
retryDelayMs = Math.max(retryDelayMs, Math.min(MAX_WRITE_RETRY_DELAY_MS, flushIntervalMs *
|
|
179
|
+
2 ** Math.max(...nextRetries.map((item) => item.writeRetries))));
|
|
180
|
+
}
|
|
181
|
+
if (exhausted > 0) {
|
|
182
|
+
dropped += exhausted;
|
|
183
|
+
writeDrops += exhausted;
|
|
184
|
+
}
|
|
162
185
|
logger.warn("[proxy] lifecycle metadata write failed", {
|
|
186
|
+
path,
|
|
187
|
+
retrying: retryable.length,
|
|
188
|
+
dropped: exhausted,
|
|
163
189
|
error: error instanceof Error ? error.message : String(error),
|
|
164
190
|
});
|
|
165
191
|
}
|
|
166
192
|
}
|
|
193
|
+
if (retries.length > 0) {
|
|
194
|
+
// Keep retried records ahead of newly admitted records. This preserves
|
|
195
|
+
// per-file sequence order while continuing to keep request paths async.
|
|
196
|
+
queue.unshift(...retries);
|
|
197
|
+
nextFlushDelayMs = Math.max(nextFlushDelayMs ?? 0, retryDelayMs || flushIntervalMs);
|
|
198
|
+
}
|
|
167
199
|
}
|
|
168
200
|
finally {
|
|
169
201
|
inFlight = Math.max(0, inFlight - batch.length);
|
|
@@ -179,21 +211,27 @@ function startFlush() {
|
|
|
179
211
|
if (flushInFlight === currentFlush) {
|
|
180
212
|
flushInFlight = undefined;
|
|
181
213
|
}
|
|
182
|
-
|
|
214
|
+
const delayMs = nextFlushDelayMs;
|
|
215
|
+
nextFlushDelayMs = undefined;
|
|
216
|
+
scheduleFlush(delayMs);
|
|
183
217
|
}, () => {
|
|
184
218
|
if (flushInFlight === currentFlush) {
|
|
185
219
|
flushInFlight = undefined;
|
|
186
220
|
}
|
|
187
|
-
|
|
221
|
+
const delayMs = nextFlushDelayMs;
|
|
222
|
+
nextFlushDelayMs = undefined;
|
|
223
|
+
scheduleFlush(delayMs);
|
|
188
224
|
});
|
|
189
225
|
return currentFlush;
|
|
190
226
|
}
|
|
191
227
|
export function configureProxyLifecycleLogger(options) {
|
|
192
228
|
clearScheduledFlush();
|
|
229
|
+
nextFlushDelayMs = undefined;
|
|
193
230
|
loggerEnabled = false;
|
|
194
231
|
lifecycleLogDir = undefined;
|
|
195
232
|
queueCapacity = positiveInteger(options.queueCapacity, DEFAULT_QUEUE_CAPACITY);
|
|
196
233
|
batchSize = positiveInteger(options.batchSize, DEFAULT_BATCH_SIZE);
|
|
234
|
+
maxWriteRetries = positiveInteger(options.maxWriteRetries, DEFAULT_MAX_WRITE_RETRIES);
|
|
197
235
|
flushIntervalMs = positiveInteger(options.flushIntervalMs, DEFAULT_FLUSH_INTERVAL_MS);
|
|
198
236
|
if (options.enabled && options.logDir) {
|
|
199
237
|
try {
|
|
@@ -268,6 +306,7 @@ export function logProxyLifecycleEvent(input) {
|
|
|
268
306
|
logDir: lifecycleLogDir,
|
|
269
307
|
date: String(record.timestamp).slice(0, 10),
|
|
270
308
|
record,
|
|
309
|
+
writeRetries: 0,
|
|
271
310
|
});
|
|
272
311
|
enqueued += 1;
|
|
273
312
|
scheduleFlush();
|
|
@@ -303,6 +342,7 @@ export function getProxyLifecycleLoggerSnapshot() {
|
|
|
303
342
|
invalidDrops,
|
|
304
343
|
writeDrops,
|
|
305
344
|
writeFailures,
|
|
345
|
+
writeRetries,
|
|
306
346
|
pending: queue.length,
|
|
307
347
|
inFlight,
|
|
308
348
|
flushing: flushInFlight !== undefined,
|
|
@@ -315,6 +355,7 @@ export function resetProxyLifecycleLoggerForTests() {
|
|
|
315
355
|
queueCapacity = DEFAULT_QUEUE_CAPACITY;
|
|
316
356
|
batchSize = DEFAULT_BATCH_SIZE;
|
|
317
357
|
flushIntervalMs = DEFAULT_FLUSH_INTERVAL_MS;
|
|
358
|
+
maxWriteRetries = DEFAULT_MAX_WRITE_RETRIES;
|
|
318
359
|
processInstanceId = randomUUID();
|
|
319
360
|
sessionHashKey = randomBytes(32);
|
|
320
361
|
nextSequence = 1;
|
|
@@ -326,7 +367,16 @@ export function resetProxyLifecycleLoggerForTests() {
|
|
|
326
367
|
invalidDrops = 0;
|
|
327
368
|
writeDrops = 0;
|
|
328
369
|
writeFailures = 0;
|
|
370
|
+
writeRetries = 0;
|
|
329
371
|
inFlight = 0;
|
|
330
372
|
queue = [];
|
|
331
373
|
flushInFlight = undefined;
|
|
374
|
+
nextFlushDelayMs = undefined;
|
|
375
|
+
appendLifecycleFile = appendFile;
|
|
332
376
|
}
|
|
377
|
+
/** Isolated failure injection for lifecycle durability tests. */
|
|
378
|
+
export const __proxyLifecycleTestHooks = {
|
|
379
|
+
setAppendFileForTests(append) {
|
|
380
|
+
appendLifecycleFile = append;
|
|
381
|
+
},
|
|
382
|
+
};
|
|
@@ -77,6 +77,8 @@ export declare function recordFinalSuccess(accountLabel?: string, accountType?:
|
|
|
77
77
|
export declare function recordAttemptError(accountLabel: string, accountType: string, status: number, rateLimitKind?: "transient" | "quota"): void;
|
|
78
78
|
export declare function recordFinalError(status: number, accountLabel?: string, accountType?: string, details?: ProxyTerminalErrorDetails): void;
|
|
79
79
|
export declare function getStats(): ProxyStats;
|
|
80
|
+
/** Return the process-local coherent snapshot without filesystem reconciliation. */
|
|
81
|
+
export declare function getUsageSnapshot(): ProxyUsageStatsSnapshot;
|
|
80
82
|
export declare function getReconciledStats(): Promise<ProxyStats>;
|
|
81
83
|
export declare function getReconciledUsageSnapshot(): Promise<ProxyUsageStatsSnapshot>;
|
|
82
84
|
export declare function getAccountStats(label: string): AccountStats | undefined;
|
package/dist/proxy/usageStats.js
CHANGED
|
@@ -1121,6 +1121,10 @@ export function recordFinalError(status, accountLabel, accountType, details) {
|
|
|
1121
1121
|
export function getStats() {
|
|
1122
1122
|
return defaultStore.getStats();
|
|
1123
1123
|
}
|
|
1124
|
+
/** Return the process-local coherent snapshot without filesystem reconciliation. */
|
|
1125
|
+
export function getUsageSnapshot() {
|
|
1126
|
+
return defaultStore.getUsageSnapshot();
|
|
1127
|
+
}
|
|
1124
1128
|
export async function getReconciledStats() {
|
|
1125
1129
|
return defaultStore.reconcile();
|
|
1126
1130
|
}
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -1246,6 +1246,8 @@ export type ProxyLifecycleLoggerSnapshot = {
|
|
|
1246
1246
|
invalidDrops: number;
|
|
1247
1247
|
writeDrops: number;
|
|
1248
1248
|
writeFailures: number;
|
|
1249
|
+
/** Events requeued after a transient lifecycle metadata write failure. */
|
|
1250
|
+
writeRetries: number;
|
|
1249
1251
|
pending: number;
|
|
1250
1252
|
inFlight: number;
|
|
1251
1253
|
flushing: boolean;
|
|
@@ -1257,12 +1259,15 @@ export type ProxyLifecycleLoggerOptions = {
|
|
|
1257
1259
|
queueCapacity?: number;
|
|
1258
1260
|
batchSize?: number;
|
|
1259
1261
|
flushIntervalMs?: number;
|
|
1262
|
+
/** Bounded retries for a metadata batch that cannot be appended immediately. */
|
|
1263
|
+
maxWriteRetries?: number;
|
|
1260
1264
|
};
|
|
1261
1265
|
/** Serialized lifecycle line awaiting a bounded batch write. */
|
|
1262
1266
|
export type QueuedProxyLifecycleEvent = {
|
|
1263
1267
|
logDir: string;
|
|
1264
1268
|
date: string;
|
|
1265
1269
|
record: Record<string, unknown>;
|
|
1270
|
+
writeRetries: number;
|
|
1266
1271
|
};
|
|
1267
1272
|
/** Percentile summary used by offline proxy log analysis. */
|
|
1268
1273
|
export type ProxyLatencySummary = {
|
|
@@ -2167,6 +2172,8 @@ export type StatusStats = {
|
|
|
2167
2172
|
terminalErrorDetailsComparable?: boolean;
|
|
2168
2173
|
terminalErrorDetailsMissing?: number;
|
|
2169
2174
|
terminalErrorDetailsExcess?: number;
|
|
2175
|
+
/** Whether this status response reconciled shared state or used local memory. */
|
|
2176
|
+
snapshotSource?: "reconciled" | "memory";
|
|
2170
2177
|
accounts?: {
|
|
2171
2178
|
label: string;
|
|
2172
2179
|
type: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.9.1",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|
|
@@ -145,6 +145,7 @@
|
|
|
145
145
|
"test:model-capabilities": "npx tsx test/continuous-test-suite-model-capabilities.ts",
|
|
146
146
|
"test:agent-runtime:vitest": "pnpm exec vitest run test/agentRuntime.test.ts",
|
|
147
147
|
"test:retry-after:vitest": "pnpm exec vitest run test/retryAfter.test.ts",
|
|
148
|
+
"test:websearch-grounding": "npx tsx test/continuous-test-suite-websearch-grounding.ts",
|
|
148
149
|
"test:ci": "pnpm run test && pnpm run test:client && pnpm run test:hitl",
|
|
149
150
|
"// CI tier — fast, no live AI calls, safe for every commit": "",
|
|
150
151
|
"test:tool-routing": "npx tsx test/continuous-test-suite-tool-routing.ts",
|
|
@@ -152,7 +153,7 @@
|
|
|
152
153
|
"test:system-messages": "npx tsx test/continuous-test-suite-system-messages.ts",
|
|
153
154
|
"test:test-stubs": "npx tsx test/continuous-test-suite-test-stubs.ts",
|
|
154
155
|
"test:tool-routing-semantic": "npx tsx test/continuous-test-suite-tool-routing-semantic.ts",
|
|
155
|
-
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:file-detector-extension && pnpm run test:file-detector-magic-bytes && pnpm run test:mcp:infra && pnpm run test:mcp:bash && pnpm run test:mcp:limits && pnpm run test:mcp:spans && pnpm run test:autoresearch:redis && pnpm run test:tool-routing && pnpm run test:tool-routing-cli && pnpm run test:tool-dedup && pnpm run test:model-pool && pnpm run test:litellm-context && pnpm run test:dedup-execute-map && pnpm run test:step-budget-guard && pnpm run test:agent-plumbing && pnpm run test:tool-execution-recorder && pnpm run test:proxy-terminal-errors && pnpm run test:system-messages && pnpm run test:tool-routing-semantic && pnpm run test:anthropic-tools-policy && pnpm run test:sagemaker-tools && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop && pnpm run test:model-capabilities && pnpm run test:agent-runtime:vitest && pnpm run test:agent-delegation && pnpm run test:retry-after:vitest && pnpm run test:sampling-params && pnpm run test:structured-recovery && pnpm run test:prompt-redaction && pnpm run test:mcp-result-cache && pnpm run test:test-stubs && pnpm run test:model-not-found-retryable",
|
|
156
|
+
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:file-detector-extension && pnpm run test:file-detector-magic-bytes && pnpm run test:mcp:infra && pnpm run test:mcp:bash && pnpm run test:mcp:limits && pnpm run test:mcp:spans && pnpm run test:autoresearch:redis && pnpm run test:tool-routing && pnpm run test:tool-routing-cli && pnpm run test:tool-dedup && pnpm run test:model-pool && pnpm run test:litellm-context && pnpm run test:dedup-execute-map && pnpm run test:step-budget-guard && pnpm run test:agent-plumbing && pnpm run test:tool-execution-recorder && pnpm run test:proxy-terminal-errors && pnpm run test:system-messages && pnpm run test:tool-routing-semantic && pnpm run test:anthropic-tools-policy && pnpm run test:sagemaker-tools && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop && pnpm run test:model-capabilities && pnpm run test:agent-runtime:vitest && pnpm run test:agent-delegation && pnpm run test:retry-after:vitest && pnpm run test:sampling-params && pnpm run test:structured-recovery && pnpm run test:prompt-redaction && pnpm run test:mcp-result-cache && pnpm run test:test-stubs && pnpm run test:model-not-found-retryable && pnpm run test:websearch-grounding",
|
|
156
157
|
"// CI tier — live providers, runs only when API keys are present (test:credentials and test:dynamic make real provider calls when keys are set, so they live here, not in test:unit)": "",
|
|
157
158
|
"test:live": "pnpm run test:providers && pnpm run test:mcp:http && pnpm run test:mcp:sdk && pnpm run test:mcp:cli && pnpm run test:observability && pnpm run test:context && pnpm run test:memory && pnpm run test:tool-reliability && pnpm run test:evaluation && pnpm run test:autoresearch && pnpm run test:credentials && pnpm run test:dynamic",
|
|
158
159
|
"// CI tier — product output (image/video/TTS/PPT) — costs $$ per run": "",
|