@juspay/neurolink 10.7.0 → 10.8.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 +17 -0
- package/dist/adapters/replicate/predictionLifecycle.d.ts +1 -1
- package/dist/adapters/replicate/predictionLifecycle.js +50 -45
- package/dist/agent/directTools.d.ts +2 -2
- package/dist/browser/neurolink.min.js +373 -373
- package/dist/cli/commands/proxyAnalyze.js +1 -1
- package/dist/core/baseProvider.d.ts +1 -0
- package/dist/core/baseProvider.js +74 -11
- package/dist/core/modules/TelemetryHandler.d.ts +5 -1
- package/dist/core/modules/TelemetryHandler.js +20 -0
- package/dist/lib/adapters/replicate/predictionLifecycle.d.ts +1 -1
- package/dist/lib/adapters/replicate/predictionLifecycle.js +50 -45
- package/dist/lib/core/baseProvider.d.ts +1 -0
- package/dist/lib/core/baseProvider.js +74 -11
- package/dist/lib/core/modules/TelemetryHandler.d.ts +5 -1
- package/dist/lib/core/modules/TelemetryHandler.js +20 -0
- package/dist/lib/mcp/httpRateLimiter.js +14 -21
- package/dist/lib/proxy/proxyAnalysis.js +27 -9
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +16 -2
- package/dist/lib/server/routes/claudeProxyRoutes.js +15 -9
- package/dist/lib/types/generate.d.ts +16 -0
- package/dist/lib/types/proxy.d.ts +3 -0
- package/dist/lib/utils/errorHandling.d.ts +2 -0
- package/dist/lib/utils/errorHandling.js +2 -0
- package/dist/lib/utils/pdfProcessor.js +2 -2
- package/dist/lib/utils/providerRetry.d.ts +5 -1
- package/dist/lib/utils/providerRetry.js +34 -8
- package/dist/lib/utils/retryAfter.d.ts +7 -0
- package/dist/lib/utils/retryAfter.js +44 -0
- package/dist/mcp/httpRateLimiter.js +14 -21
- package/dist/proxy/proxyAnalysis.js +27 -9
- package/dist/server/routes/claudeProxyRoutes.d.ts +16 -2
- package/dist/server/routes/claudeProxyRoutes.js +15 -9
- package/dist/types/generate.d.ts +16 -0
- package/dist/types/proxy.d.ts +3 -0
- package/dist/utils/errorHandling.d.ts +2 -0
- package/dist/utils/errorHandling.js +2 -0
- package/dist/utils/pdfProcessor.js +2 -2
- package/dist/utils/providerRetry.d.ts +5 -1
- package/dist/utils/providerRetry.js +34 -8
- package/dist/utils/retryAfter.d.ts +7 -0
- package/dist/utils/retryAfter.js +43 -0
- package/package.json +3 -2
|
@@ -562,16 +562,18 @@ function buildRoutingDecision(args) {
|
|
|
562
562
|
const { accounts, orderedAccounts, metricsByKey, evaluatedAt, strategy, primaryKey, quotaRoutingEnabled, quotaOrdered, sessionSoftLimit, sessionResetToleranceMs, rotationOffset, } = args;
|
|
563
563
|
const sourceIndexes = new Map(accounts.map((account, index) => [account.key, index]));
|
|
564
564
|
const configuredPrimaryMatched = !!primaryKey && accounts.some((account) => account.key === primaryKey);
|
|
565
|
-
const candidates =
|
|
565
|
+
const candidates = [];
|
|
566
|
+
for (const account of orderedAccounts) {
|
|
566
567
|
const metrics = metricsByKey.get(account.key);
|
|
567
568
|
if (!metrics) {
|
|
568
|
-
|
|
569
|
+
logger.warn(`[proxy] routing evidence omitted because metrics are missing for account=${account.label}`);
|
|
570
|
+
return undefined;
|
|
569
571
|
}
|
|
570
|
-
|
|
572
|
+
candidates.push({
|
|
571
573
|
account: account.label,
|
|
572
574
|
accountType: account.type,
|
|
573
|
-
sourceIndex: sourceIndexes.get(account.key) ??
|
|
574
|
-
rank,
|
|
575
|
+
sourceIndex: sourceIndexes.get(account.key) ?? candidates.length,
|
|
576
|
+
rank: candidates.length,
|
|
575
577
|
configuredPrimary: !!primaryKey && account.key === primaryKey,
|
|
576
578
|
usable: metrics.usable,
|
|
577
579
|
saturated: metrics.saturated,
|
|
@@ -598,8 +600,8 @@ function buildRoutingDecision(args) {
|
|
|
598
600
|
weeklyResetAt: Number.isFinite(metrics.weeklyReset)
|
|
599
601
|
? metrics.weeklyReset
|
|
600
602
|
: null,
|
|
601
|
-
};
|
|
602
|
-
}
|
|
603
|
+
});
|
|
604
|
+
}
|
|
603
605
|
const initialAccount = orderedAccounts[0];
|
|
604
606
|
let mode;
|
|
605
607
|
let selectionReason;
|
|
@@ -684,7 +686,7 @@ function selectClaudeProxyAccountOrder(args) {
|
|
|
684
686
|
accountSortMetrics(account.key, evaluatedAt, sessionSoftLimit, sessionResetToleranceMs),
|
|
685
687
|
]));
|
|
686
688
|
}
|
|
687
|
-
|
|
689
|
+
const routingDecision = buildRoutingDecision({
|
|
688
690
|
accounts: enabledAccounts,
|
|
689
691
|
orderedAccounts,
|
|
690
692
|
metricsByKey,
|
|
@@ -696,7 +698,10 @@ function selectClaudeProxyAccountOrder(args) {
|
|
|
696
698
|
sessionSoftLimit,
|
|
697
699
|
sessionResetToleranceMs,
|
|
698
700
|
rotationOffset,
|
|
699
|
-
})
|
|
701
|
+
});
|
|
702
|
+
if (routingDecision) {
|
|
703
|
+
setRoutingDecision(routingDecision);
|
|
704
|
+
}
|
|
700
705
|
return orderedAccounts;
|
|
701
706
|
}
|
|
702
707
|
// ---------------------------------------------------------------------------
|
|
@@ -4896,6 +4901,7 @@ export const __testHooks = {
|
|
|
4896
4901
|
rotationOffset: 0,
|
|
4897
4902
|
});
|
|
4898
4903
|
},
|
|
4904
|
+
buildRoutingDecision,
|
|
4899
4905
|
resetEpochToMs,
|
|
4900
4906
|
seedRuntimeQuotasFromDisk,
|
|
4901
4907
|
reconcileEligibleAccountRuntimeState,
|
package/dist/types/generate.d.ts
CHANGED
|
@@ -1418,9 +1418,25 @@ export type TextGenerationResult = {
|
|
|
1418
1418
|
/**
|
|
1419
1419
|
* Enhanced result type with optional analytics/evaluation
|
|
1420
1420
|
*/
|
|
1421
|
+
export type TTSMetadata = {
|
|
1422
|
+
/** Whether TTS synthesis was invoked. False indicates TTS was skipped. */
|
|
1423
|
+
attempted: boolean;
|
|
1424
|
+
/** Whether TTS synthesis completed successfully. */
|
|
1425
|
+
success: boolean;
|
|
1426
|
+
/** Structured synthesis error details, present only when synthesis failed. */
|
|
1427
|
+
error?: {
|
|
1428
|
+
code: string;
|
|
1429
|
+
message: string;
|
|
1430
|
+
retriable?: boolean;
|
|
1431
|
+
};
|
|
1432
|
+
/** TTS synthesis time in milliseconds. */
|
|
1433
|
+
latency?: number;
|
|
1434
|
+
};
|
|
1421
1435
|
export type EnhancedGenerateResult = GenerateResult & {
|
|
1422
1436
|
analytics?: AnalyticsData;
|
|
1423
1437
|
evaluation?: EvaluationData;
|
|
1438
|
+
/** Outcome metadata when TTS was enabled for this generation. */
|
|
1439
|
+
ttsMetadata?: TTSMetadata;
|
|
1424
1440
|
};
|
|
1425
1441
|
/**
|
|
1426
1442
|
* NL-004: Model alias/deprecation configuration.
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -1341,6 +1341,9 @@ export type ProxyAnalysisReport = {
|
|
|
1341
1341
|
initialAccounts: Record<string, number>;
|
|
1342
1342
|
finalAccountChanges: number;
|
|
1343
1343
|
finalOutsideCandidateSet: number;
|
|
1344
|
+
/** Number of routing decisions aggregated before sampling records. */
|
|
1345
|
+
totalRecords: number;
|
|
1346
|
+
/** Most recent bounded sample retained for offline inspection. */
|
|
1344
1347
|
records: ProxyAnalysisRoutingRecord[];
|
|
1345
1348
|
};
|
|
1346
1349
|
accounts: ProxyAnalysisAccount[];
|
|
@@ -70,6 +70,7 @@ export declare class NeuroLinkError extends Error {
|
|
|
70
70
|
readonly category: ErrorCategory;
|
|
71
71
|
readonly severity: ErrorSeverity;
|
|
72
72
|
readonly retriable: boolean;
|
|
73
|
+
readonly retryAfterMs?: number;
|
|
73
74
|
readonly context: Record<string, unknown>;
|
|
74
75
|
readonly timestamp: Date;
|
|
75
76
|
readonly toolName?: string;
|
|
@@ -80,6 +81,7 @@ export declare class NeuroLinkError extends Error {
|
|
|
80
81
|
category: ErrorCategory;
|
|
81
82
|
severity: ErrorSeverity;
|
|
82
83
|
retriable: boolean;
|
|
84
|
+
retryAfterMs?: number;
|
|
83
85
|
context?: Record<string, unknown>;
|
|
84
86
|
originalError?: Error;
|
|
85
87
|
toolName?: string;
|
|
@@ -87,6 +87,7 @@ export class NeuroLinkError extends Error {
|
|
|
87
87
|
category;
|
|
88
88
|
severity;
|
|
89
89
|
retriable;
|
|
90
|
+
retryAfterMs;
|
|
90
91
|
context;
|
|
91
92
|
timestamp;
|
|
92
93
|
toolName;
|
|
@@ -98,6 +99,7 @@ export class NeuroLinkError extends Error {
|
|
|
98
99
|
this.category = options.category;
|
|
99
100
|
this.severity = options.severity;
|
|
100
101
|
this.retriable = options.retriable;
|
|
102
|
+
this.retryAfterMs = options.retryAfterMs;
|
|
101
103
|
this.context = options.context || {};
|
|
102
104
|
this.timestamp = new Date();
|
|
103
105
|
this.toolName = options.toolName;
|
|
@@ -91,14 +91,14 @@ const PDF_PROVIDER_CONFIGS = {
|
|
|
91
91
|
litellm: {
|
|
92
92
|
maxSizeMB: 10,
|
|
93
93
|
maxPages: 100,
|
|
94
|
-
supportsNative:
|
|
94
|
+
supportsNative: false, // LiteLLM is a proxy — underlying model may not support native PDF; default to safe text extraction
|
|
95
95
|
requiresCitations: false,
|
|
96
96
|
apiType: "files-api",
|
|
97
97
|
},
|
|
98
98
|
"openai-compatible": {
|
|
99
99
|
maxSizeMB: 10,
|
|
100
100
|
maxPages: 100,
|
|
101
|
-
supportsNative: false,
|
|
101
|
+
supportsNative: false,
|
|
102
102
|
requiresCitations: false,
|
|
103
103
|
apiType: "files-api",
|
|
104
104
|
},
|
|
@@ -18,6 +18,10 @@ import { type Span } from "@opentelemetry/api";
|
|
|
18
18
|
export declare const MAX_PROVIDER_RETRIES = 2;
|
|
19
19
|
/** Base delay in ms for exponential backoff between retries. */
|
|
20
20
|
export declare const BASE_RETRY_DELAY_MS = 1000;
|
|
21
|
+
/** Minimum delay in ms when a retryable response provides no retry timing. */
|
|
22
|
+
export declare const NO_HINT_FLOOR_MS = 10000;
|
|
23
|
+
/** Maximum server-requested retry delay honored by provider retries. */
|
|
24
|
+
export declare const MAX_RETRY_AFTER_MS = 120000;
|
|
21
25
|
/**
|
|
22
26
|
* Check whether an error thrown by the AI SDK is retryable.
|
|
23
27
|
*
|
|
@@ -38,4 +42,4 @@ export declare function getErrorStatusCode(error: unknown): number | undefined;
|
|
|
38
42
|
* @param label - A human-readable label for log messages (e.g. "generateText", "streamText")
|
|
39
43
|
* @returns The result of the operation
|
|
40
44
|
*/
|
|
41
|
-
export declare function withProviderRetry<T>(operation: () => Promise<T>, span: Span, label: string): Promise<T>;
|
|
45
|
+
export declare function withProviderRetry<T>(operation: () => Promise<T>, span: Span | undefined, label: string, sleep?: (delayMs: number) => Promise<void>): Promise<T>;
|
|
@@ -13,12 +13,19 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @module utils/providerRetry
|
|
15
15
|
*/
|
|
16
|
+
import { NeuroLinkError } from "./errorHandling.js";
|
|
16
17
|
import { logger } from "./logger.js";
|
|
17
18
|
import { APICallError } from "./generationErrors.js";
|
|
19
|
+
import { parseRetryAfterMs } from "./retryAfter.js";
|
|
18
20
|
/** Maximum number of retry attempts after the initial call (total = 1 + MAX_PROVIDER_RETRIES). */
|
|
19
21
|
export const MAX_PROVIDER_RETRIES = 2;
|
|
20
22
|
/** Base delay in ms for exponential backoff between retries. */
|
|
21
23
|
export const BASE_RETRY_DELAY_MS = 1000;
|
|
24
|
+
/** Minimum delay in ms when a retryable response provides no retry timing. */
|
|
25
|
+
export const NO_HINT_FLOOR_MS = 10_000;
|
|
26
|
+
/** Maximum server-requested retry delay honored by provider retries. */
|
|
27
|
+
export const MAX_RETRY_AFTER_MS = 120_000;
|
|
28
|
+
const sleepWithTimeout = (delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
22
29
|
/**
|
|
23
30
|
* Check whether an error thrown by the AI SDK is retryable.
|
|
24
31
|
*
|
|
@@ -31,6 +38,9 @@ export function isRetryableProviderError(error) {
|
|
|
31
38
|
if (APICallError.isInstance(error)) {
|
|
32
39
|
return error.isRetryable;
|
|
33
40
|
}
|
|
41
|
+
if (error instanceof NeuroLinkError) {
|
|
42
|
+
return error.retriable;
|
|
43
|
+
}
|
|
34
44
|
// Fallback: duck-type for status codes on errors that aren't APICallError
|
|
35
45
|
if (error && typeof error === "object" && "statusCode" in error) {
|
|
36
46
|
const statusCode = error.statusCode;
|
|
@@ -50,6 +60,18 @@ export function getErrorStatusCode(error) {
|
|
|
50
60
|
}
|
|
51
61
|
return undefined;
|
|
52
62
|
}
|
|
63
|
+
function getRetryAfterMs(error) {
|
|
64
|
+
if (APICallError.isInstance(error) && error.responseHeaders) {
|
|
65
|
+
const parsedDelay = parseRetryAfterMs(error.responseHeaders);
|
|
66
|
+
if (parsedDelay !== undefined) {
|
|
67
|
+
return parsedDelay;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (error instanceof NeuroLinkError && error.retryAfterMs !== undefined) {
|
|
71
|
+
return error.retryAfterMs;
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
53
75
|
/**
|
|
54
76
|
* Execute a provider call with instrumented retry logic.
|
|
55
77
|
*
|
|
@@ -58,12 +80,12 @@ export function getErrorStatusCode(error) {
|
|
|
58
80
|
* @param label - A human-readable label for log messages (e.g. "generateText", "streamText")
|
|
59
81
|
* @returns The result of the operation
|
|
60
82
|
*/
|
|
61
|
-
export async function withProviderRetry(operation, span, label) {
|
|
83
|
+
export async function withProviderRetry(operation, span, label, sleep = sleepWithTimeout) {
|
|
62
84
|
for (let attempt = 0; attempt <= MAX_PROVIDER_RETRIES; attempt++) {
|
|
63
85
|
try {
|
|
64
86
|
const result = await operation();
|
|
65
87
|
// Record how many attempts it took on the span
|
|
66
|
-
span
|
|
88
|
+
span?.setAttribute("gen_ai.provider.total_attempts", attempt + 1);
|
|
67
89
|
if (attempt > 0) {
|
|
68
90
|
logger.info(`[providerRetry] ${label} succeeded after ${attempt + 1} attempts`);
|
|
69
91
|
}
|
|
@@ -75,9 +97,9 @@ export async function withProviderRetry(operation, span, label) {
|
|
|
75
97
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
76
98
|
if (!retryable || attempt === MAX_PROVIDER_RETRIES) {
|
|
77
99
|
// Record failure details before re-throwing
|
|
78
|
-
span
|
|
100
|
+
span?.setAttribute("gen_ai.provider.total_attempts", attempt + 1);
|
|
79
101
|
if (attempt > 0) {
|
|
80
|
-
span
|
|
102
|
+
span?.setAttribute("gen_ai.provider.retries_exhausted", true);
|
|
81
103
|
}
|
|
82
104
|
logger.warn(`[providerRetry] ${label} failed (non-retryable or retries exhausted)`, {
|
|
83
105
|
attempt: attempt + 1,
|
|
@@ -87,10 +109,14 @@ export async function withProviderRetry(operation, span, label) {
|
|
|
87
109
|
});
|
|
88
110
|
throw error;
|
|
89
111
|
}
|
|
90
|
-
|
|
91
|
-
const
|
|
112
|
+
const retryAfterMs = getRetryAfterMs(error);
|
|
113
|
+
const boundedRetryAfterMs = retryAfterMs === undefined
|
|
114
|
+
? undefined
|
|
115
|
+
: Math.min(MAX_RETRY_AFTER_MS, Math.max(0, retryAfterMs));
|
|
116
|
+
const delay = boundedRetryAfterMs ??
|
|
117
|
+
Math.max(BASE_RETRY_DELAY_MS * Math.pow(2, attempt), NO_HINT_FLOOR_MS);
|
|
92
118
|
// Record retry event on the OTel span
|
|
93
|
-
span
|
|
119
|
+
span?.addEvent("gen_ai.provider.retry", {
|
|
94
120
|
"retry.attempt": attempt + 1,
|
|
95
121
|
"retry.delay_ms": delay,
|
|
96
122
|
...(statusCode !== undefined && { "retry.status_code": statusCode }),
|
|
@@ -103,7 +129,7 @@ export async function withProviderRetry(operation, span, label) {
|
|
|
103
129
|
statusCode,
|
|
104
130
|
error: errorMessage,
|
|
105
131
|
});
|
|
106
|
-
await
|
|
132
|
+
await sleep(delay);
|
|
107
133
|
}
|
|
108
134
|
}
|
|
109
135
|
// This should never be reached due to the throw inside the loop,
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse standard and commonly used rate-limit response headers.
|
|
3
|
+
*
|
|
4
|
+
* @returns The requested delay in milliseconds, or undefined when the
|
|
5
|
+
* response does not provide a usable rate-limit delay.
|
|
6
|
+
*/
|
|
7
|
+
export declare function parseRetryAfterMs(headers: Pick<Headers, "get"> | Readonly<Record<string, string>>): number | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
function getHeader(headers, headerName) {
|
|
2
|
+
if ("get" in headers && typeof headers.get === "function") {
|
|
3
|
+
return headers.get(headerName);
|
|
4
|
+
}
|
|
5
|
+
const normalizedHeaderName = headerName.toLowerCase();
|
|
6
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
7
|
+
if (name.toLowerCase() === normalizedHeaderName) {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Parse standard and commonly used rate-limit response headers.
|
|
15
|
+
*
|
|
16
|
+
* @returns The requested delay in milliseconds, or undefined when the
|
|
17
|
+
* response does not provide a usable rate-limit delay.
|
|
18
|
+
*/
|
|
19
|
+
export function parseRetryAfterMs(headers) {
|
|
20
|
+
const retryAfter = getHeader(headers, "Retry-After");
|
|
21
|
+
if (retryAfter) {
|
|
22
|
+
const seconds = parseInt(retryAfter, 10);
|
|
23
|
+
if (!Number.isNaN(seconds)) {
|
|
24
|
+
return Math.max(0, seconds * 1000);
|
|
25
|
+
}
|
|
26
|
+
const retryDate = new Date(retryAfter);
|
|
27
|
+
if (!Number.isNaN(retryDate.getTime())) {
|
|
28
|
+
return Math.max(0, retryDate.getTime() - Date.now());
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const rateLimitReset = getHeader(headers, "X-RateLimit-Reset");
|
|
32
|
+
if (rateLimitReset) {
|
|
33
|
+
const resetTimestamp = parseInt(rateLimitReset, 10);
|
|
34
|
+
if (!Number.isNaN(resetTimestamp)) {
|
|
35
|
+
const resetTime = resetTimestamp > 1e12 ? resetTimestamp : resetTimestamp * 1000;
|
|
36
|
+
return Math.max(0, resetTime - Date.now());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (getHeader(headers, "X-RateLimit-Remaining") === "0") {
|
|
40
|
+
return 1000;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.8.0",
|
|
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": {
|
|
@@ -144,6 +144,7 @@
|
|
|
144
144
|
"test:model-pool": "pnpm run test:model-pool:vitest && npx tsx test/continuous-test-suite-model-pool.ts",
|
|
145
145
|
"test:model-capabilities:vitest": "pnpm exec vitest run test/modelCapabilities.test.ts",
|
|
146
146
|
"test:agent-runtime:vitest": "pnpm exec vitest run test/agentRuntime.test.ts test/agentDelegation.test.ts test/agentPlumbing.test.ts test/toolExecutionRecorder.test.ts test/samplingParams.test.ts test/structuredRecovery.test.ts",
|
|
147
|
+
"test:retry-after:vitest": "pnpm exec vitest run test/retryAfter.test.ts",
|
|
147
148
|
"test:ci": "pnpm run test && pnpm run test:client && pnpm run test:hitl",
|
|
148
149
|
"// CI tier — fast, no live AI calls, safe for every commit": "",
|
|
149
150
|
"test:unit:vitest": "pnpm exec vitest run test/toolRouting.test.ts",
|
|
@@ -152,7 +153,7 @@
|
|
|
152
153
|
"test:system-messages:vitest": "pnpm exec vitest run test/systemMessages.test.ts",
|
|
153
154
|
"test:tool-routing-semantic:vitest": "pnpm exec vitest run test/toolRoutingSemantic.test.ts",
|
|
154
155
|
"test:tool-routing-semantic": "pnpm run test:tool-routing-semantic:vitest && 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:unit:vitest && pnpm run test:tool-routing-cli:vitest && pnpm run test:tool-dedup:vitest && pnpm run test:model-pool:vitest && pnpm run test:litellm-context:vitest && pnpm run test:step-budget-guard: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 && pnpm run test:model-capabilities:vitest && pnpm run test:agent-runtime:vitest",
|
|
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:unit:vitest && pnpm run test:tool-routing-cli:vitest && pnpm run test:tool-dedup:vitest && pnpm run test:model-pool:vitest && pnpm run test:litellm-context:vitest && pnpm run test:step-budget-guard: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 && pnpm run test:model-capabilities:vitest && pnpm run test:agent-runtime:vitest && pnpm run test:retry-after:vitest",
|
|
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": "",
|