@juspay/neurolink 9.92.1 → 9.92.3
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/browser/neurolink.min.js +364 -364
- package/dist/lib/providers/sagemaker/language-model.d.ts +15 -2
- package/dist/lib/providers/sagemaker/language-model.js +52 -25
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +16 -18
- package/dist/lib/server/routes/claudeProxyRoutes.js +40 -53
- package/dist/providers/sagemaker/language-model.d.ts +15 -2
- package/dist/providers/sagemaker/language-model.js +52 -25
- package/dist/server/routes/claudeProxyRoutes.d.ts +16 -18
- package/dist/server/routes/claudeProxyRoutes.js +40 -53
- package/package.json +3 -2
|
@@ -53,11 +53,6 @@ const BLOCKED_UPSTREAM_HEADERS = new Set([
|
|
|
53
53
|
let primaryAccountIndex = 0;
|
|
54
54
|
/** Track account count so we can reset primaryAccountIndex when it changes. */
|
|
55
55
|
let lastKnownAccountCount = 0;
|
|
56
|
-
/** Stable account key used by legacy fixed-config route factories. Runtime
|
|
57
|
-
* config providers pass the request generation's primary key explicitly.
|
|
58
|
-
* When undefined, home semantics retain insertion-order behavior. */
|
|
59
|
-
let configuredPrimaryAccountKey;
|
|
60
|
-
let configuredAccountAllowlist;
|
|
61
56
|
const MAX_AUTH_RETRIES = 5;
|
|
62
57
|
const MAX_TRANSIENT_SAME_ACCOUNT_RETRIES = 2;
|
|
63
58
|
const TRANSIENT_SAME_ACCOUNT_RETRY_DELAYS_MS = [250, 1_000];
|
|
@@ -129,7 +124,7 @@ function advancePrimaryIfCurrent(accountKey, enabledCount, primaryAccountKey) {
|
|
|
129
124
|
* no key is configured or the key cannot be matched (account disabled/
|
|
130
125
|
* removed). The resolution is per-request because enabledAccounts membership
|
|
131
126
|
* can shift between requests. */
|
|
132
|
-
function resolveHomeIndex(enabledAccounts, primaryAccountKey
|
|
127
|
+
function resolveHomeIndex(enabledAccounts, primaryAccountKey) {
|
|
133
128
|
if (!primaryAccountKey) {
|
|
134
129
|
return 0;
|
|
135
130
|
}
|
|
@@ -140,7 +135,7 @@ function resolveHomeIndex(enabledAccounts, primaryAccountKey = configuredPrimary
|
|
|
140
135
|
* primaryAccountIndex back to its index so traffic returns to the preferred
|
|
141
136
|
* account once its rate limit window expires. Called at the start of each
|
|
142
137
|
* request. Home is resolved fresh per call via resolveHomeIndex. */
|
|
143
|
-
function maybeResetPrimaryToHome(enabledAccounts, primaryAccountKey
|
|
138
|
+
function maybeResetPrimaryToHome(enabledAccounts, primaryAccountKey) {
|
|
144
139
|
if (enabledAccounts.length <= 1) {
|
|
145
140
|
return;
|
|
146
141
|
}
|
|
@@ -463,28 +458,30 @@ function accountSortMetrics(accountKey, now, sessionSoftLimit, sessionResetToler
|
|
|
463
458
|
}
|
|
464
459
|
/**
|
|
465
460
|
* Order accounts to MAXIMIZE quota utilization (fill-first, smart order):
|
|
466
|
-
* spend the
|
|
467
|
-
*
|
|
461
|
+
* spend the overall weekly allowance that expires SOONEST first, so quota
|
|
462
|
+
* cannot disappear while traffic is consuming a newer weekly window. The 5h
|
|
463
|
+
* window remains an availability boundary: a session at its soft limit is
|
|
464
|
+
* temporarily demoted until that session resets.
|
|
468
465
|
*
|
|
469
466
|
* Priority among usable accounts:
|
|
470
467
|
* 1. no quota data yet — probe first: one request reveals its windows and
|
|
471
468
|
* self-corrects the ordering. (Ranking unknowns last would starve them
|
|
472
469
|
* forever: never picked → never observed → never comparable.)
|
|
473
470
|
* 2. session headroom before session-saturated (>= soft limit or
|
|
474
|
-
* "throttled") —
|
|
475
|
-
*
|
|
476
|
-
*
|
|
477
|
-
*
|
|
478
|
-
*
|
|
479
|
-
*
|
|
480
|
-
* 5. highest weekly utilization — finish off the one closest to done
|
|
471
|
+
* "throttled") — do not re-hammer an urgent weekly account while its 5h
|
|
472
|
+
* capacity is temporarily unavailable.
|
|
473
|
+
* 3. soonest WEEKLY (7d) reset — consume the oldest overall allowance
|
|
474
|
+
* before it expires.
|
|
475
|
+
* 4. soonest SESSION (5h) reset — decides equal-weekly or fresh-weekly ties,
|
|
476
|
+
* using tolerance buckets for comparator stability.
|
|
477
|
+
* 5. highest weekly utilization — finish off the one closest to done.
|
|
481
478
|
* 6. configured primary account, then insertion order
|
|
482
|
-
*
|
|
483
|
-
*
|
|
479
|
+
* Saturated pairs are ordered by soonest 5h recovery first, then weekly reset,
|
|
480
|
+
* because neither can consume more quota until session capacity returns.
|
|
484
481
|
* Cooling/rejected accounts sort last, soonest-back-to-service first, as
|
|
485
482
|
* last resort.
|
|
486
483
|
*/
|
|
487
|
-
function orderAccountsByQuota(accounts, now, primaryKey
|
|
484
|
+
function orderAccountsByQuota(accounts, now, primaryKey, sessionSoftLimit = getSessionSoftLimit(), sessionResetToleranceMs = getSessionResetToleranceMs()) {
|
|
488
485
|
const metrics = (key) => accountSortMetrics(key, now, sessionSoftLimit, sessionResetToleranceMs);
|
|
489
486
|
return [...accounts].sort((a, b) => {
|
|
490
487
|
const ma = metrics(a.key);
|
|
@@ -503,14 +500,21 @@ function orderAccountsByQuota(accounts, now, primaryKey = configuredPrimaryAccou
|
|
|
503
500
|
if (ma.saturated !== mb.saturated) {
|
|
504
501
|
return ma.saturated ? 1 : -1;
|
|
505
502
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
503
|
+
if (ma.saturated && mb.saturated) {
|
|
504
|
+
if (ma.sessionResetBucket !== mb.sessionResetBucket) {
|
|
505
|
+
return ma.sessionResetBucket - mb.sessionResetBucket;
|
|
506
|
+
}
|
|
507
|
+
if (ma.weeklyReset !== mb.weeklyReset) {
|
|
508
|
+
return ma.weeklyReset - mb.weeklyReset;
|
|
509
|
+
}
|
|
511
510
|
}
|
|
512
|
-
|
|
513
|
-
|
|
511
|
+
else {
|
|
512
|
+
if (ma.weeklyReset !== mb.weeklyReset) {
|
|
513
|
+
return ma.weeklyReset - mb.weeklyReset;
|
|
514
|
+
}
|
|
515
|
+
if (ma.sessionResetBucket !== mb.sessionResetBucket) {
|
|
516
|
+
return ma.sessionResetBucket - mb.sessionResetBucket;
|
|
517
|
+
}
|
|
514
518
|
}
|
|
515
519
|
if (ma.weeklyUsed !== mb.weeklyUsed) {
|
|
516
520
|
return mb.weeklyUsed - ma.weeklyUsed;
|
|
@@ -1538,7 +1542,7 @@ async function handleClaudePassthroughJsonResponse(args) {
|
|
|
1538
1542
|
return responseJson;
|
|
1539
1543
|
}
|
|
1540
1544
|
async function loadClaudeProxyAccounts(args) {
|
|
1541
|
-
const { ctx, body, tracer, requestStartTime, accountStrategy, primaryAccountKey
|
|
1545
|
+
const { ctx, body, tracer, requestStartTime, accountStrategy, primaryAccountKey, accountAllowlist, quotaRoutingEnabled = isQuotaRoutingEnabled(), sessionSoftLimit = getSessionSoftLimit(), sessionResetToleranceMs = getSessionResetToleranceMs(), buildLoggedClaudeError, } = args;
|
|
1542
1546
|
const fs = await import("fs");
|
|
1543
1547
|
const os = await import("os");
|
|
1544
1548
|
const accounts = [];
|
|
@@ -1722,10 +1726,16 @@ async function loadClaudeProxyAccounts(args) {
|
|
|
1722
1726
|
const quotaOrdered = accountStrategy === "fill-first" &&
|
|
1723
1727
|
orderedAccounts.length > 1 &&
|
|
1724
1728
|
quotaRoutingEnabled;
|
|
1729
|
+
if (!quotaOrdered && accountStrategy === "fill-first") {
|
|
1730
|
+
// Apply the request-scoped home before deriving this request's order. A
|
|
1731
|
+
// hot-reloaded primary change must not lag by one request. Round-robin
|
|
1732
|
+
// deliberately skips this reset so its rotating index remains strict.
|
|
1733
|
+
maybeResetPrimaryToHome(enabledAccounts, primaryAccountKey);
|
|
1734
|
+
}
|
|
1725
1735
|
if (quotaOrdered) {
|
|
1726
|
-
// Fill-first with a smart fill order: spend the account whose window
|
|
1727
|
-
// soonest
|
|
1728
|
-
//
|
|
1736
|
+
// Fill-first with a smart fill order: spend the account whose weekly window
|
|
1737
|
+
// expires soonest while temporarily demoting sessions without headroom.
|
|
1738
|
+
// Supersedes the static home/primary index.
|
|
1729
1739
|
orderedAccounts = orderAccountsByQuota(enabledAccounts, Date.now(), primaryAccountKey, sessionSoftLimit, sessionResetToleranceMs);
|
|
1730
1740
|
if (logger.shouldLog("debug")) {
|
|
1731
1741
|
logger.debug(`[proxy] quota-ordered fill sequence: ${orderedAccounts
|
|
@@ -3791,15 +3801,6 @@ async function handleAnthropicRoutedClaudeRequest(args) {
|
|
|
3791
3801
|
attemptNumber: 0,
|
|
3792
3802
|
};
|
|
3793
3803
|
const acctSelectionSpan = tracer?.startAccountSelection();
|
|
3794
|
-
// Try to return to the home primary account if its cooling has expired.
|
|
3795
|
-
// Skipped under quota routing, where the fill order is derived per-request
|
|
3796
|
-
// from live quota (soonest-reset-first) rather than a static home index.
|
|
3797
|
-
const usingQuotaOrder = accountStrategy === "fill-first" &&
|
|
3798
|
-
enabledAccounts.length > 1 &&
|
|
3799
|
-
quotaRoutingEnabled;
|
|
3800
|
-
if (!usingQuotaOrder) {
|
|
3801
|
-
maybeResetPrimaryToHome(enabledAccounts, primaryAccountKey);
|
|
3802
|
-
}
|
|
3803
3804
|
// Never re-hammer accounts with a known active cooldown. When every account
|
|
3804
3805
|
// is cooling, report the earliest persisted retry time without an upstream
|
|
3805
3806
|
// call; restarting the proxy must not erase or bypass this quarantine.
|
|
@@ -4174,10 +4175,6 @@ export function createClaudeProxyRoutes(modelRouter, basePath = "", accountStrat
|
|
|
4174
4175
|
const runtimeConfigProvider = isClaudeProxyRouteRuntimeOptions(accountAllowlistOrRuntimeOptions)
|
|
4175
4176
|
? accountAllowlistOrRuntimeOptions.runtimeConfigProvider
|
|
4176
4177
|
: undefined;
|
|
4177
|
-
configuredPrimaryAccountKey = primaryAccountKey;
|
|
4178
|
-
configuredAccountAllowlist = accountAllowlist
|
|
4179
|
-
? new Set(accountAllowlist)
|
|
4180
|
-
: undefined;
|
|
4181
4178
|
return {
|
|
4182
4179
|
prefix: `${basePath}/v1`,
|
|
4183
4180
|
routes: [
|
|
@@ -4608,14 +4605,6 @@ export const __testHooks = {
|
|
|
4608
4605
|
const state = accountRuntimeState.get(key);
|
|
4609
4606
|
return state ? { ...state } : undefined;
|
|
4610
4607
|
},
|
|
4611
|
-
setConfiguredPrimaryAccountKey: (key) => {
|
|
4612
|
-
configuredPrimaryAccountKey = key;
|
|
4613
|
-
},
|
|
4614
|
-
getConfiguredPrimaryAccountKey: () => configuredPrimaryAccountKey,
|
|
4615
|
-
setConfiguredAccountAllowlist: (allowlist) => {
|
|
4616
|
-
configuredAccountAllowlist = allowlist ? new Set(allowlist) : undefined;
|
|
4617
|
-
},
|
|
4618
|
-
getConfiguredAccountAllowlist: () => configuredAccountAllowlist ? [...configuredAccountAllowlist] : undefined,
|
|
4619
4608
|
setPrimaryAccountIndex: (index) => {
|
|
4620
4609
|
primaryAccountIndex = index;
|
|
4621
4610
|
},
|
|
@@ -4631,8 +4620,6 @@ export const __testHooks = {
|
|
|
4631
4620
|
transientCooldownAdmissionSchedules.clear();
|
|
4632
4621
|
primaryAccountIndex = 0;
|
|
4633
4622
|
lastKnownAccountCount = 0;
|
|
4634
|
-
configuredPrimaryAccountKey = undefined;
|
|
4635
|
-
configuredAccountAllowlist = undefined;
|
|
4636
4623
|
},
|
|
4637
4624
|
polyfillOAuthBody: (bodyStr, isClaudeClientRequest) => polyfillOAuthBody(bodyStr, "test-account-token", null, isClaudeClientRequest),
|
|
4638
4625
|
isAntiAbuseConstruction429,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.92.
|
|
3
|
+
"version": "9.92.3",
|
|
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": {
|
|
@@ -128,6 +128,7 @@
|
|
|
128
128
|
"test:autoresearch": "npx tsx test/continuous-test-suite-autoresearch.ts",
|
|
129
129
|
"test:autoresearch:redis": "npx tsx test/continuous-test-suite-autoresearch-redis.ts",
|
|
130
130
|
"test:anthropic-tools-policy": "npx tsx test/continuous-test-suite-anthropic-tools-policy.ts",
|
|
131
|
+
"test:sagemaker-tools": "npx tsx test/continuous-test-suite-sagemaker-tools.ts",
|
|
131
132
|
"test:anthropic-multimodal": "npx tsx test/continuous-test-suite-anthropic-multimodal.ts",
|
|
132
133
|
"test:excel-interop": "npx tsx test/continuous-test-suite-excel-interop.ts",
|
|
133
134
|
"test:envguard": "npx tsx test/helpers/envGuard.test.ts",
|
|
@@ -145,7 +146,7 @@
|
|
|
145
146
|
"test:system-messages:vitest": "pnpm exec vitest run test/systemMessages.test.ts",
|
|
146
147
|
"test:tool-routing-semantic:vitest": "pnpm exec vitest run test/toolRoutingSemantic.test.ts",
|
|
147
148
|
"test:tool-routing-semantic": "pnpm run test:tool-routing-semantic:vitest && npx tsx test/continuous-test-suite-tool-routing-semantic.ts",
|
|
148
|
-
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:file-detector-extension && 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:unit:vitest && pnpm run test:tool-routing-cli:vitest && pnpm run test:tool-dedup:vitest && pnpm run test:model-pool:vitest && pnpm run test:system-messages:vitest && pnpm run test:tool-routing-semantic:vitest && pnpm run test:anthropic-tools-policy && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop",
|
|
149
|
+
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:file-detector-extension && 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:unit:vitest && pnpm run test:tool-routing-cli:vitest && pnpm run test:tool-dedup:vitest && pnpm run test:model-pool:vitest && pnpm run test:system-messages:vitest && pnpm run test:tool-routing-semantic:vitest && pnpm run test:anthropic-tools-policy && pnpm run test:sagemaker-tools && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop",
|
|
149
150
|
"// 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)": "",
|
|
150
151
|
"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",
|
|
151
152
|
"// CI tier — product output (image/video/TTS/PPT) — costs $$ per run": "",
|