@juspay/neurolink 9.79.1 → 9.79.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 +337 -332
- package/dist/core/modules/GenerationHandler.js +43 -1
- package/dist/core/modules/structuredOutputPolicy.d.ts +42 -6
- package/dist/core/modules/structuredOutputPolicy.js +58 -7
- package/dist/lib/core/modules/GenerationHandler.js +43 -1
- package/dist/lib/core/modules/structuredOutputPolicy.d.ts +42 -6
- package/dist/lib/core/modules/structuredOutputPolicy.js +58 -7
- package/dist/lib/processors/document/ExcelProcessor.js +9 -1
- package/dist/lib/providers/anthropic.js +37 -41
- package/dist/lib/providers/anthropicImageBlocks.d.ts +47 -0
- package/dist/lib/providers/anthropicImageBlocks.js +223 -0
- package/dist/lib/providers/googleNativeGemini3.d.ts +26 -0
- package/dist/lib/providers/googleNativeGemini3.js +48 -0
- package/dist/lib/providers/googleVertex.d.ts +16 -0
- package/dist/lib/providers/googleVertex.js +200 -24
- package/dist/lib/proxy/oauthFetch.js +26 -14
- package/dist/lib/proxy/proxyTracer.d.ts +7 -1
- package/dist/lib/proxy/proxyTracer.js +29 -0
- package/dist/lib/proxy/systemRelocation.d.ts +21 -0
- package/dist/lib/proxy/systemRelocation.js +51 -0
- package/dist/lib/server/routes/claudeProxyRoutes.js +147 -19
- package/dist/lib/types/proxy.d.ts +10 -0
- package/dist/processors/document/ExcelProcessor.js +9 -1
- package/dist/providers/anthropic.js +37 -41
- package/dist/providers/anthropicImageBlocks.d.ts +47 -0
- package/dist/providers/anthropicImageBlocks.js +222 -0
- package/dist/providers/googleNativeGemini3.d.ts +26 -0
- package/dist/providers/googleNativeGemini3.js +48 -0
- package/dist/providers/googleVertex.d.ts +16 -0
- package/dist/providers/googleVertex.js +200 -24
- package/dist/proxy/oauthFetch.js +26 -14
- package/dist/proxy/proxyTracer.d.ts +7 -1
- package/dist/proxy/proxyTracer.js +29 -0
- package/dist/proxy/systemRelocation.d.ts +21 -0
- package/dist/proxy/systemRelocation.js +50 -0
- package/dist/server/routes/claudeProxyRoutes.js +147 -19
- package/dist/types/proxy.d.ts +10 -0
- package/package.json +8 -2
|
@@ -20,6 +20,7 @@ import { tracers } from "../../telemetry/tracers.js";
|
|
|
20
20
|
import { withSpan } from "../../telemetry/withSpan.js";
|
|
21
21
|
import { ProxyTracer, recordFallbackAttempt } from "../../proxy/proxyTracer.js";
|
|
22
22
|
import { createRawStreamCapture } from "../../proxy/rawStreamCapture.js";
|
|
23
|
+
import { relocateClientSystemIntoMessages } from "../../proxy/systemRelocation.js";
|
|
23
24
|
import { logBodyCapture, logRequest, logRequestAttempt, logStreamError, } from "../../proxy/requestLogger.js";
|
|
24
25
|
import { createSSEInterceptor } from "../../proxy/sseInterceptor.js";
|
|
25
26
|
import { needsRefresh, persistTokens, refreshToken, } from "../../proxy/tokenRefresh.js";
|
|
@@ -332,6 +333,63 @@ async function maybeRefreshClaudeSnapshot(accountLabel, accountKey, headers, bod
|
|
|
332
333
|
}
|
|
333
334
|
return next;
|
|
334
335
|
}
|
|
336
|
+
/**
|
|
337
|
+
* Parse response-side details (model, finish reason, invoked tools) from a
|
|
338
|
+
* non-streaming Anthropic reply so they can be recorded on the trace span.
|
|
339
|
+
*/
|
|
340
|
+
function extractResponseInfo(responseJson) {
|
|
341
|
+
const info = {};
|
|
342
|
+
if (!responseJson || typeof responseJson !== "object") {
|
|
343
|
+
return info;
|
|
344
|
+
}
|
|
345
|
+
const r = responseJson;
|
|
346
|
+
if (typeof r.model === "string") {
|
|
347
|
+
info.responseModel = r.model;
|
|
348
|
+
}
|
|
349
|
+
if (typeof r.stop_reason === "string") {
|
|
350
|
+
info.finishReason = r.stop_reason;
|
|
351
|
+
}
|
|
352
|
+
if (typeof r.stop_sequence === "string") {
|
|
353
|
+
info.stopSequence = r.stop_sequence;
|
|
354
|
+
}
|
|
355
|
+
if (Array.isArray(r.content)) {
|
|
356
|
+
const toolCalls = r.content
|
|
357
|
+
.filter((b) => !!b &&
|
|
358
|
+
typeof b === "object" &&
|
|
359
|
+
b.type === "tool_use")
|
|
360
|
+
.map((b) => String(b.name ?? ""))
|
|
361
|
+
.filter((n) => n.length > 0);
|
|
362
|
+
if (toolCalls.length > 0) {
|
|
363
|
+
info.toolCalls = toolCalls;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return info;
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Build response-info from streaming telemetry (responding model, finish
|
|
370
|
+
* reason, and the tools the model invoked via tool_use content blocks) so the
|
|
371
|
+
* streaming path records the same gen_ai.response.* attributes as non-streaming.
|
|
372
|
+
*/
|
|
373
|
+
function responseInfoFromStream(data) {
|
|
374
|
+
const info = {};
|
|
375
|
+
if (data.model) {
|
|
376
|
+
info.responseModel = data.model;
|
|
377
|
+
}
|
|
378
|
+
if (data.stopReason) {
|
|
379
|
+
info.finishReason = data.stopReason;
|
|
380
|
+
}
|
|
381
|
+
if (data.stopSequence) {
|
|
382
|
+
info.stopSequence = data.stopSequence;
|
|
383
|
+
}
|
|
384
|
+
const toolCalls = (data.contentBlocks ?? [])
|
|
385
|
+
.filter((b) => b.type === "tool_use")
|
|
386
|
+
.map((b) => String(b.toolName ?? ""))
|
|
387
|
+
.filter((n) => n.length > 0);
|
|
388
|
+
if (toolCalls.length > 0) {
|
|
389
|
+
info.toolCalls = toolCalls;
|
|
390
|
+
}
|
|
391
|
+
return info;
|
|
392
|
+
}
|
|
335
393
|
/**
|
|
336
394
|
* Polyfill the request body for OAuth accounts.
|
|
337
395
|
* Claude Code injects a billing header, agent block, and metadata.user_id
|
|
@@ -350,25 +408,21 @@ function polyfillOAuthBody(bodyStr, accountToken, snapshot, preferredSessionId)
|
|
|
350
408
|
text: snapshot?.body?.agentBlock ||
|
|
351
409
|
"You are a Claude agent, built on Anthropic's Claude Agent SDK.",
|
|
352
410
|
};
|
|
353
|
-
// Normalise system to array
|
|
354
|
-
// IMPORTANT: We append (not prepend) to preserve the client's cache
|
|
355
|
-
// prefix chain. Anthropic's prompt caching uses prefix matching — if we
|
|
356
|
-
// insert anything before the client's system blocks, we invalidate all
|
|
357
|
-
// cached content (tools, system prompt, message history).
|
|
411
|
+
// Normalise system to an array, then route by client type.
|
|
358
412
|
//
|
|
359
|
-
//
|
|
360
|
-
//
|
|
361
|
-
//
|
|
362
|
-
//
|
|
363
|
-
//
|
|
364
|
-
//
|
|
413
|
+
// The subscription/OAuth path only accepts a `system` it recognises as the
|
|
414
|
+
// genuine Claude Code prompt. A real CC client sends its own billing + agent
|
|
415
|
+
// identity blocks alongside the canonical prompt — we keep those in place and
|
|
416
|
+
// just stabilise the volatile billing `cch`. A custom client (Curator) sends
|
|
417
|
+
// its own arbitrary system prompt with NO agent block; left in `system` it is
|
|
418
|
+
// rejected as `rate_limit_error: "Error"`, so we relocate it into the message
|
|
419
|
+
// stream and send only the recognised billing + agent blocks as `system`.
|
|
365
420
|
if (parsed.system) {
|
|
366
421
|
if (typeof parsed.system === "string") {
|
|
367
422
|
parsed.system = [{ type: "text", text: parsed.system }];
|
|
368
423
|
}
|
|
369
424
|
if (Array.isArray(parsed.system)) {
|
|
370
|
-
// Find
|
|
371
|
-
// the client placed them (typically at system[0])
|
|
425
|
+
// Find existing billing/agent blocks wherever the client placed them.
|
|
372
426
|
const billingIdx = parsed.system.findIndex((b) => typeof b.text === "string" &&
|
|
373
427
|
b.text.includes("x-anthropic-billing-header"));
|
|
374
428
|
const agentIdx = parsed.system.findIndex((b) => typeof b.text === "string" && b.text.includes("Claude Agent SDK"));
|
|
@@ -376,17 +430,29 @@ function polyfillOAuthBody(bodyStr, accountToken, snapshot, preferredSessionId)
|
|
|
376
430
|
type: "text",
|
|
377
431
|
text: buildStableClaudeCodeBillingHeader(parsed.system[billingIdx]?.text ?? snapshot?.body?.billingHeader),
|
|
378
432
|
};
|
|
379
|
-
//
|
|
433
|
+
// A genuine Claude Code client supplies its own agent-identity block;
|
|
434
|
+
// a custom client (Curator) does not.
|
|
435
|
+
const isClaudeCodeClient = agentIdx >= 0;
|
|
436
|
+
// Strip billing/agent from their positions (reverse order so indices
|
|
437
|
+
// stay valid). What remains is the client's "extra" system content.
|
|
380
438
|
const indicesToRemove = [billingIdx, agentIdx]
|
|
381
439
|
.filter((i) => i >= 0)
|
|
382
440
|
.sort((a, b) => b - a);
|
|
383
441
|
for (const idx of indicesToRemove) {
|
|
384
442
|
parsed.system.splice(idx, 1);
|
|
385
443
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
444
|
+
if (!isClaudeCodeClient && parsed.system.length > 0) {
|
|
445
|
+
// Non-CC client: relocate its system into the message stream so the
|
|
446
|
+
// subscription/OAuth path accepts the request, then send only the
|
|
447
|
+
// recognised billing + agent blocks as `system`.
|
|
448
|
+
relocateClientSystemIntoMessages(parsed, parsed.system);
|
|
449
|
+
parsed.system = [billingBlock, agentBlock];
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Genuine Claude Code (or no extra blocks): keep the recognised system
|
|
453
|
+
// and append the deterministic billing + agent blocks at the end.
|
|
454
|
+
parsed.system = [...parsed.system, billingBlock, agentBlock];
|
|
455
|
+
}
|
|
390
456
|
}
|
|
391
457
|
}
|
|
392
458
|
else {
|
|
@@ -680,6 +746,7 @@ async function handleClaudePassthroughStreamResponse(args) {
|
|
|
680
746
|
cacheReadTokens: data.usage.cacheReadInputTokens,
|
|
681
747
|
});
|
|
682
748
|
capturedTracer.logStreamEvents(data.events);
|
|
749
|
+
capturedTracer.setResponseInfo(responseInfoFromStream(data));
|
|
683
750
|
const rateLimit5h = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-5h-utilization") ?? "");
|
|
684
751
|
const rateLimit7d = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-7d-utilization") ?? "");
|
|
685
752
|
const usageUpdate = {
|
|
@@ -871,6 +938,7 @@ async function handleClaudePassthroughJsonResponse(args) {
|
|
|
871
938
|
tracer.setUsage(usageWithRates);
|
|
872
939
|
}
|
|
873
940
|
}
|
|
941
|
+
tracer.setResponseInfo(extractResponseInfo(responseJson));
|
|
874
942
|
tracer.recordMetrics();
|
|
875
943
|
const responseJsonStr = JSON.stringify(responseJson);
|
|
876
944
|
tracer.recordBodySizes(bodyStr.length, responseJsonStr.length);
|
|
@@ -1556,6 +1624,7 @@ function attachAnthropicSuccessStreamTelemetry(args) {
|
|
|
1556
1624
|
cacheReadTokens: data.usage.cacheReadInputTokens,
|
|
1557
1625
|
});
|
|
1558
1626
|
capturedTracer.logStreamEvents(data.events);
|
|
1627
|
+
capturedTracer.setResponseInfo(responseInfoFromStream(data));
|
|
1559
1628
|
const rateLimit5h = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-5h-utilization") ?? "");
|
|
1560
1629
|
const rateLimit7d = parseFloat(capturedResponse.headers.get("anthropic-ratelimit-unified-7d-utilization") ?? "");
|
|
1561
1630
|
const usageUpdate = {
|
|
@@ -1773,6 +1842,7 @@ async function handleAnthropicJsonSuccessResponse(args) {
|
|
|
1773
1842
|
tracer.setUsage(usageWithRates);
|
|
1774
1843
|
}
|
|
1775
1844
|
}
|
|
1845
|
+
tracer.setResponseInfo(extractResponseInfo(responseJson));
|
|
1776
1846
|
tracer.recordMetrics();
|
|
1777
1847
|
const responseJsonStr = JSON.stringify(responseJson);
|
|
1778
1848
|
tracer.recordBodySizes(finalBodyStr.length, responseJsonStr.length);
|
|
@@ -1875,6 +1945,7 @@ async function handleAnthropicSuccessfulRetryResponse(args) {
|
|
|
1875
1945
|
cacheReadTokens: data.usage.cacheReadInputTokens,
|
|
1876
1946
|
});
|
|
1877
1947
|
capturedTracer.logStreamEvents(data.events);
|
|
1948
|
+
capturedTracer.setResponseInfo(responseInfoFromStream(data));
|
|
1878
1949
|
capturedTracer.logUpstreamResponseHeaders(Object.fromEntries([...capturedRetryResp.headers.entries()]));
|
|
1879
1950
|
capturedTracer.recordMetrics();
|
|
1880
1951
|
capturedTracer.recordBodySizes(capturedRetryRequestBytes, data.totalBytesReceived);
|
|
@@ -1961,6 +2032,7 @@ async function handleAnthropicSuccessfulRetryResponse(args) {
|
|
|
1961
2032
|
cacheReadTokens: retryUsage.cache_read_input_tokens ?? 0,
|
|
1962
2033
|
});
|
|
1963
2034
|
}
|
|
2035
|
+
tracer.setResponseInfo(extractResponseInfo(retryJson));
|
|
1964
2036
|
tracer.recordMetrics();
|
|
1965
2037
|
const retryJsonStr = JSON.stringify(retryJson);
|
|
1966
2038
|
tracer.recordBodySizes(finalBodyStr.length, retryJsonStr.length);
|
|
@@ -2083,7 +2155,14 @@ async function handleAnthropicAuthRetry(args) {
|
|
|
2083
2155
|
currentLastError = retryBody;
|
|
2084
2156
|
logger.debug(`[proxy] retry ${authRetry + 1} failed: ${retryStatus} ${retryBody.substring(0, 120)}`);
|
|
2085
2157
|
recordAttemptError(account.label, account.type, retryStatus);
|
|
2086
|
-
|
|
2158
|
+
// A real rate-limit 429 rotates accounts. But an anti-abuse / construction
|
|
2159
|
+
// 429 (no rate-limit headers, body "Error") is NOT a real rate limit:
|
|
2160
|
+
// advancing the primary or rotating cannot help and only burns quota. Skip
|
|
2161
|
+
// the rotate path for it so it falls through to the terminal error return
|
|
2162
|
+
// below, surfacing the truthful upstream error — mirroring the initial
|
|
2163
|
+
// fetch path's fast-fail (isAntiAbuseConstruction429).
|
|
2164
|
+
if (retryStatus === 429 &&
|
|
2165
|
+
!isAntiAbuseConstruction429(retryRespHeaders, retryBody)) {
|
|
2087
2166
|
currentSawRateLimit = true;
|
|
2088
2167
|
advancePrimaryIfCurrent(account.key, enabledAccounts.length, orderedAccounts[0]?.key);
|
|
2089
2168
|
break;
|
|
@@ -2373,6 +2452,13 @@ function createClaudeRequestRuntimeContext(args) {
|
|
|
2373
2452
|
model: body.model,
|
|
2374
2453
|
stream: body.stream ?? false,
|
|
2375
2454
|
toolCount: Array.isArray(body.tools) ? body.tools.length : 0,
|
|
2455
|
+
toolNames: Array.isArray(body.tools)
|
|
2456
|
+
? body.tools
|
|
2457
|
+
.map((t) => t && typeof t === "object" && "name" in t
|
|
2458
|
+
? String(t.name ?? "")
|
|
2459
|
+
: "")
|
|
2460
|
+
.filter((n) => n.length > 0)
|
|
2461
|
+
: undefined,
|
|
2376
2462
|
sessionId: ctx.headers["x-neurolink-session-id"] ??
|
|
2377
2463
|
ctx.headers["x-claude-code-session-id"] ??
|
|
2378
2464
|
undefined,
|
|
@@ -2649,6 +2735,24 @@ async function prepareAnthropicAccountAttempt(args) {
|
|
|
2649
2735
|
upstreamSpan,
|
|
2650
2736
|
};
|
|
2651
2737
|
}
|
|
2738
|
+
/**
|
|
2739
|
+
* Detect Anthropic's anti-abuse / request-construction 429.
|
|
2740
|
+
*
|
|
2741
|
+
* The subscription/OAuth path rejects requests it does not recognise as genuine
|
|
2742
|
+
* Claude Code traffic with a 429 `rate_limit_error` whose message is literally
|
|
2743
|
+
* "Error" and which carries NONE of the real rate-limit headers (no retry-after,
|
|
2744
|
+
* no anthropic-ratelimit-*). This is NOT a capacity limit — retrying or rotating
|
|
2745
|
+
* accounts cannot fix it and only burns quota, so the caller must fail fast and
|
|
2746
|
+
* surface the truthful upstream error instead of "all accounts rate-limited".
|
|
2747
|
+
*/
|
|
2748
|
+
function isAntiAbuseConstruction429(headers, body) {
|
|
2749
|
+
const hasRetryAfter = !!headers["retry-after"];
|
|
2750
|
+
const hasRateLimitHeaders = Object.keys(headers).some((k) => k.toLowerCase().startsWith("anthropic-ratelimit-"));
|
|
2751
|
+
if (hasRetryAfter || hasRateLimitHeaders) {
|
|
2752
|
+
return false;
|
|
2753
|
+
}
|
|
2754
|
+
return (body.includes("rate_limit_error") && /"message"\s*:\s*"Error"/.test(body));
|
|
2755
|
+
}
|
|
2652
2756
|
async function fetchAnthropicAccountResponse(args) {
|
|
2653
2757
|
const { url, headers, finalBodyStr, account, accountState: _accountState2, enabledAccounts: _enabledAccounts, orderedAccounts: _orderedAccounts, tracer, logAttempt, logProxyBody, fetchStartMs, attemptNumber, currentLastError, currentSawRateLimit, currentSawNetworkError, upstreamSpan, } = args;
|
|
2654
2758
|
let lastError = currentLastError;
|
|
@@ -2719,6 +2823,30 @@ async function fetchAnthropicAccountResponse(args) {
|
|
|
2719
2823
|
responseStatus: 429,
|
|
2720
2824
|
durationMs: Date.now() - fetchStartMs,
|
|
2721
2825
|
});
|
|
2826
|
+
// Anti-abuse / request-construction 429 (no rate-limit headers, body
|
|
2827
|
+
// "Error"): rotating accounts cannot help and only burns quota. Fail fast
|
|
2828
|
+
// and surface the truthful upstream error instead of the misleading
|
|
2829
|
+
// "all accounts rate-limited" after 44 wasted attempts.
|
|
2830
|
+
if (isAntiAbuseConstruction429(errRespHeaders, String(lastError))) {
|
|
2831
|
+
logger.always(`[proxy] ← 429 account=${account.label} anti-abuse/construction rejection (no ratelimit headers, body="Error") — NOT a real rate limit; returning upstream error without rotating`);
|
|
2832
|
+
logAttempt(429, "construction_rejection", String(lastError));
|
|
2833
|
+
tracer?.setError("construction_rejection", String(lastError).slice(0, 500));
|
|
2834
|
+
currentUpstreamSpan?.end();
|
|
2835
|
+
const passthrough = new Response(String(lastError), {
|
|
2836
|
+
status: 429,
|
|
2837
|
+
headers: {
|
|
2838
|
+
"content-type": errRespHeaders["content-type"] ?? "application/json",
|
|
2839
|
+
},
|
|
2840
|
+
});
|
|
2841
|
+
return {
|
|
2842
|
+
continueLoop: false,
|
|
2843
|
+
response: passthrough,
|
|
2844
|
+
lastError,
|
|
2845
|
+
sawRateLimit,
|
|
2846
|
+
sawNetworkError,
|
|
2847
|
+
upstreamSpan: undefined,
|
|
2848
|
+
};
|
|
2849
|
+
}
|
|
2722
2850
|
logger.always(`[proxy] ← 429 account=${account.label} retry-after=${retryAfterMs}ms (upstream) ratelimit-status=${errRespHeaders["anthropic-ratelimit-unified-status"] ?? "unknown"}`);
|
|
2723
2851
|
logAttempt(429, "rate_limit_error", String(lastError));
|
|
2724
2852
|
tracer?.setError("rate_limit_error", String(lastError).slice(0, 500));
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -771,10 +771,20 @@ export type ProxyRequestContext = {
|
|
|
771
771
|
model: string;
|
|
772
772
|
stream: boolean;
|
|
773
773
|
toolCount: number;
|
|
774
|
+
/** Names of the tools advertised in the request (what the caller exposed). */
|
|
775
|
+
toolNames?: string[];
|
|
774
776
|
sessionId?: string;
|
|
775
777
|
userAgent?: string;
|
|
776
778
|
clientApp?: string;
|
|
777
779
|
};
|
|
780
|
+
/** Response-side details parsed from the upstream reply (model, finish, tools). */
|
|
781
|
+
export type ResponseInfoContext = {
|
|
782
|
+
responseModel?: string;
|
|
783
|
+
finishReason?: string;
|
|
784
|
+
stopSequence?: string;
|
|
785
|
+
/** Names of the tools the model actually invoked (tool_use blocks). */
|
|
786
|
+
toolCalls?: string[];
|
|
787
|
+
};
|
|
778
788
|
/** Context recorded when an account is selected for a proxy request. */
|
|
779
789
|
export type AccountSelectionContext = {
|
|
780
790
|
strategy: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.79.
|
|
3
|
+
"version": "9.79.3",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applications with 21+ providers: OpenAI, Anthropic, Google AI Studio, Google Vertex, AWS Bedrock, Azure OpenAI, Mistral, LiteLLM, SageMaker, Hugging Face, Ollama, OpenAI-compatible, OpenRouter, DeepSeek, NVIDIA NIM, LM Studio, llama.cpp, plus voice (OpenAI TTS, ElevenLabs, Deepgram, Azure Speech).",
|
|
6
6
|
"author": {
|
|
@@ -118,6 +118,9 @@
|
|
|
118
118
|
"test:auth": "npx tsx test/continuous-test-suite-auth.ts",
|
|
119
119
|
"test:autoresearch": "npx tsx test/continuous-test-suite-autoresearch.ts",
|
|
120
120
|
"test:autoresearch:redis": "npx tsx test/continuous-test-suite-autoresearch-redis.ts",
|
|
121
|
+
"test:anthropic-tools-policy": "npx tsx test/continuous-test-suite-anthropic-tools-policy.ts",
|
|
122
|
+
"test:anthropic-multimodal": "npx tsx test/continuous-test-suite-anthropic-multimodal.ts",
|
|
123
|
+
"test:excel-interop": "npx tsx test/continuous-test-suite-excel-interop.ts",
|
|
121
124
|
"test:envguard": "npx tsx test/helpers/envGuard.test.ts",
|
|
122
125
|
"test:tool-routing-cli:vitest": "pnpm exec vitest run test/toolRoutingCli.test.ts",
|
|
123
126
|
"test:tool-routing-cli": "pnpm run test:tool-routing-cli:vitest && npx tsx test/continuous-test-suite-tool-routing-cli.ts",
|
|
@@ -131,7 +134,7 @@
|
|
|
131
134
|
"test:tool-routing": "pnpm run test:unit:vitest && npx tsx test/continuous-test-suite-tool-routing.ts",
|
|
132
135
|
"test:tool-routing-semantic:vitest": "pnpm exec vitest run test/toolRoutingSemantic.test.ts",
|
|
133
136
|
"test:tool-routing-semantic": "pnpm run test:tool-routing-semantic:vitest && npx tsx test/continuous-test-suite-tool-routing-semantic.ts",
|
|
134
|
-
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && 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:tool-routing-semantic:vitest",
|
|
137
|
+
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && 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:tool-routing-semantic:vitest && pnpm run test:anthropic-tools-policy && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop",
|
|
135
138
|
"// 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)": "",
|
|
136
139
|
"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",
|
|
137
140
|
"// CI tier — product output (image/video/TTS/PPT) — costs $$ per run": "",
|
|
@@ -598,6 +601,9 @@
|
|
|
598
601
|
"rollup@>=4.0.0 <4.59.0": ">=4.59.0",
|
|
599
602
|
"shell-quote@<1.8.4": ">=1.8.4",
|
|
600
603
|
"undici@>=8.0.0": ">=7.24.0 <8.0.0"
|
|
604
|
+
},
|
|
605
|
+
"patchedDependencies": {
|
|
606
|
+
"mammoth@1.12.0": "patches/mammoth@1.12.0.patch"
|
|
601
607
|
}
|
|
602
608
|
},
|
|
603
609
|
"os": [
|