@juspay/neurolink 10.8.21 → 10.9.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 +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 +3 -2
- package/dist/lib/agent/directTools.d.ts +65 -0
- package/dist/lib/agent/directTools.js +86 -50
- package/dist/lib/proxy/globalInstaller.d.ts +2 -0
- package/dist/lib/proxy/globalInstaller.js +9 -1
- package/dist/lib/proxy/rollingWorkerSupervisor.js +6 -4
- package/dist/proxy/globalInstaller.d.ts +2 -0
- package/dist/proxy/globalInstaller.js +9 -1
- package/dist/proxy/rollingWorkerSupervisor.js +6 -4
- package/package.json +3 -2
|
@@ -677,8 +677,9 @@ async function getRollingActivationFailure(host, port, expectedVersion) {
|
|
|
677
677
|
failure.workerExitCode === null
|
|
678
678
|
? `exitCode=${failure.workerExitCode ?? "none"}`
|
|
679
679
|
: null,
|
|
680
|
-
typeof failure.workerExitSignal === "string"
|
|
681
|
-
|
|
680
|
+
typeof failure.workerExitSignal === "string" ||
|
|
681
|
+
failure.workerExitSignal === null
|
|
682
|
+
? `exitSignal=${failure.workerExitSignal ?? "none"}`
|
|
682
683
|
: null,
|
|
683
684
|
typeof failure.supervisorAction === "string"
|
|
684
685
|
? `supervisorAction=${failure.supervisorAction}`
|
|
@@ -1,4 +1,69 @@
|
|
|
1
1
|
import type { AllToolsMap, BasicToolsMap, FilesystemToolsMap, Tool, UtilityToolsMap } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Vertex location for the websearchGrounding tool:
|
|
4
|
+
* NEUROLINK_WEBSEARCH_LOCATION, else `global`.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately does NOT inherit GOOGLE_VERTEX_LOCATION. The search models are
|
|
7
|
+
* served only from the `global`, `us` and `eu` endpoints — never from a single
|
|
8
|
+
* region — so inheriting a regional value produces a 404 for the model rather
|
|
9
|
+
* than a working search. That is not hypothetical: a deployment pinned to
|
|
10
|
+
* us-east5 for Claude-on-Vertex sent web search to us-east5 too and every
|
|
11
|
+
* query failed with NOT_FOUND.
|
|
12
|
+
*
|
|
13
|
+
* Set NEUROLINK_WEBSEARCH_LOCATION to `us` or `eu` where the multi-region
|
|
14
|
+
* endpoints are required, e.g. for data residency.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveWebsearchLocation(): string;
|
|
17
|
+
/** Model for websearchGrounding — NEUROLINK_WEBSEARCH_MODEL, else the default. */
|
|
18
|
+
export declare function resolveWebsearchModel(): string;
|
|
19
|
+
/**
|
|
20
|
+
* The generateContent request for a web search. Google Search grounding is
|
|
21
|
+
* requested natively through `config.tools`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildWebsearchRequest(model: string, query: string, maxWords: number): {
|
|
24
|
+
model: string;
|
|
25
|
+
contents: {
|
|
26
|
+
role: string;
|
|
27
|
+
parts: {
|
|
28
|
+
text: string;
|
|
29
|
+
}[];
|
|
30
|
+
}[];
|
|
31
|
+
config: {
|
|
32
|
+
tools: {
|
|
33
|
+
googleSearch: {};
|
|
34
|
+
}[];
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Display domain for one grounding chunk.
|
|
39
|
+
*
|
|
40
|
+
* Blank `domain` values count as absent, and the uri fallback is guarded by
|
|
41
|
+
* `URL.canParse` — an unparseable provider uri would otherwise throw and take
|
|
42
|
+
* the entire search down with it.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resolveGroundingDomain(web: {
|
|
45
|
+
uri?: string;
|
|
46
|
+
domain?: string;
|
|
47
|
+
}): string;
|
|
48
|
+
/**
|
|
49
|
+
* Map grounding chunks onto search results, capped at `limitedResults`.
|
|
50
|
+
* Returns an empty array when there is no usable grounding metadata, which the
|
|
51
|
+
* caller replaces with a single synthesised result.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildWebsearchResults(groundingMetadata: {
|
|
54
|
+
groundingChunks?: {
|
|
55
|
+
web?: {
|
|
56
|
+
uri?: string;
|
|
57
|
+
title?: string;
|
|
58
|
+
domain?: string;
|
|
59
|
+
};
|
|
60
|
+
}[];
|
|
61
|
+
} | undefined, searchContent: string, limitedResults: number): {
|
|
62
|
+
title: string;
|
|
63
|
+
url: string;
|
|
64
|
+
snippet: string;
|
|
65
|
+
domain: string;
|
|
66
|
+
}[];
|
|
2
67
|
/**
|
|
3
68
|
* Direct tool definitions that work immediately with Gemini/AI SDK
|
|
4
69
|
* These bypass MCP complexity and provide reliable agent functionality
|
|
@@ -6,6 +6,8 @@ import { logger } from "../utils/logger.js";
|
|
|
6
6
|
import { CSVProcessor } from "../utils/csvProcessor.js";
|
|
7
7
|
import { shouldEnableBashTool } from "../utils/toolUtils.js";
|
|
8
8
|
import { tool } from "../utils/tool.js";
|
|
9
|
+
import { withTimeout } from "../utils/async/withTimeout.js";
|
|
10
|
+
import { TIMEOUTS } from "../constants/timeouts.js";
|
|
9
11
|
const MAX_OUTPUT_BYTES = 102400; // 100KB
|
|
10
12
|
function truncateOutput(output) {
|
|
11
13
|
if (output.length > MAX_OUTPUT_BYTES) {
|
|
@@ -35,16 +37,77 @@ function resolveWithinCwd(filePath) {
|
|
|
35
37
|
}
|
|
36
38
|
return { path: resolvedPath };
|
|
37
39
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Vertex location for the websearchGrounding tool:
|
|
42
|
+
* NEUROLINK_WEBSEARCH_LOCATION, else `global`.
|
|
43
|
+
*
|
|
44
|
+
* Deliberately does NOT inherit GOOGLE_VERTEX_LOCATION. The search models are
|
|
45
|
+
* served only from the `global`, `us` and `eu` endpoints — never from a single
|
|
46
|
+
* region — so inheriting a regional value produces a 404 for the model rather
|
|
47
|
+
* than a working search. That is not hypothetical: a deployment pinned to
|
|
48
|
+
* us-east5 for Claude-on-Vertex sent web search to us-east5 too and every
|
|
49
|
+
* query failed with NOT_FOUND.
|
|
50
|
+
*
|
|
51
|
+
* Set NEUROLINK_WEBSEARCH_LOCATION to `us` or `eu` where the multi-region
|
|
52
|
+
* endpoints are required, e.g. for data residency.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveWebsearchLocation() {
|
|
55
|
+
return process.env.NEUROLINK_WEBSEARCH_LOCATION?.trim() || "global";
|
|
56
|
+
}
|
|
57
|
+
/** Model for websearchGrounding — NEUROLINK_WEBSEARCH_MODEL, else the default. */
|
|
58
|
+
export function resolveWebsearchModel() {
|
|
59
|
+
return (process.env.NEUROLINK_WEBSEARCH_MODEL?.trim() || "gemini-3.1-flash-lite");
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* The generateContent request for a web search. Google Search grounding is
|
|
63
|
+
* requested natively through `config.tools`.
|
|
64
|
+
*/
|
|
65
|
+
export function buildWebsearchRequest(model, query, maxWords) {
|
|
66
|
+
return {
|
|
67
|
+
model,
|
|
68
|
+
contents: [
|
|
69
|
+
{
|
|
70
|
+
role: "user",
|
|
71
|
+
parts: [
|
|
72
|
+
{
|
|
73
|
+
text: `Search for: "${query}". Provide a concise summary in no more than ${maxWords} words.`,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
config: { tools: [{ googleSearch: {} }] },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Display domain for one grounding chunk.
|
|
83
|
+
*
|
|
84
|
+
* Blank `domain` values count as absent, and the uri fallback is guarded by
|
|
85
|
+
* `URL.canParse` — an unparseable provider uri would otherwise throw and take
|
|
86
|
+
* the entire search down with it.
|
|
87
|
+
*/
|
|
88
|
+
export function resolveGroundingDomain(web) {
|
|
89
|
+
return (web.domain?.trim() ||
|
|
90
|
+
(web.uri && URL.canParse(web.uri) ? new URL(web.uri).hostname : "unknown"));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Map grounding chunks onto search results, capped at `limitedResults`.
|
|
94
|
+
* Returns an empty array when there is no usable grounding metadata, which the
|
|
95
|
+
* caller replaces with a single synthesised result.
|
|
96
|
+
*/
|
|
97
|
+
export function buildWebsearchResults(groundingMetadata, searchContent, limitedResults) {
|
|
98
|
+
const searchResults = [];
|
|
99
|
+
for (const chunk of groundingMetadata?.groundingChunks?.slice(0, limitedResults) ?? []) {
|
|
100
|
+
if (chunk.web) {
|
|
101
|
+
searchResults.push({
|
|
102
|
+
title: chunk.web.title || "No title",
|
|
103
|
+
url: chunk.web.uri || "",
|
|
104
|
+
// Full content — maxWords already bounds the length.
|
|
105
|
+
snippet: searchContent,
|
|
106
|
+
domain: resolveGroundingDomain(chunk.web),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return searchResults;
|
|
48
111
|
}
|
|
49
112
|
/**
|
|
50
113
|
* Direct tool definitions that work immediately with Gemini/AI SDK
|
|
@@ -593,7 +656,7 @@ export const directAgentTools = {
|
|
|
593
656
|
try {
|
|
594
657
|
const hasCredentials = process.env.GOOGLE_APPLICATION_CREDENTIALS;
|
|
595
658
|
const hasProjectId = process.env.GOOGLE_VERTEX_PROJECT;
|
|
596
|
-
const projectLocation =
|
|
659
|
+
const projectLocation = resolveWebsearchLocation();
|
|
597
660
|
if (!hasCredentials || !hasProjectId) {
|
|
598
661
|
return {
|
|
599
662
|
success: false,
|
|
@@ -605,31 +668,19 @@ export const directAgentTools = {
|
|
|
605
668
|
};
|
|
606
669
|
}
|
|
607
670
|
const limitedResults = Math.min(Math.max(maxResults, 1), 5);
|
|
608
|
-
const {
|
|
609
|
-
const vertex_ai = new
|
|
671
|
+
const { GoogleGenAI } = await import("@google/genai");
|
|
672
|
+
const vertex_ai = new GoogleGenAI({
|
|
673
|
+
vertexai: true,
|
|
610
674
|
project: hasProjectId,
|
|
611
675
|
location: projectLocation,
|
|
612
676
|
});
|
|
613
|
-
const websearchModel =
|
|
614
|
-
"gemini-2.5-flash-lite";
|
|
615
|
-
const model = vertex_ai.getGenerativeModel({
|
|
616
|
-
model: websearchModel,
|
|
617
|
-
tools: createGoogleSearchTools(),
|
|
618
|
-
});
|
|
619
|
-
// Search query with word limit constraint
|
|
620
|
-
const searchPrompt = `Search for: "${query}". Provide a concise summary in no more than ${maxWords} words.`;
|
|
677
|
+
const websearchModel = resolveWebsearchModel();
|
|
621
678
|
const startTime = Date.now();
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
role: "user",
|
|
626
|
-
parts: [{ text: searchPrompt }],
|
|
627
|
-
},
|
|
628
|
-
],
|
|
629
|
-
});
|
|
679
|
+
// A stalled Vertex call would otherwise leave the tool pending
|
|
680
|
+
// indefinitely; the outer catch turns a timeout into the failure shape.
|
|
681
|
+
const result = await withTimeout(vertex_ai.models.generateContent(buildWebsearchRequest(websearchModel, query, maxWords)), TIMEOUTS.TOOL.EXECUTION_DEFAULT_MS, "[websearchGrounding] Vertex AI web search request timed out");
|
|
630
682
|
const responseTime = Date.now() - startTime;
|
|
631
683
|
// Extract grounding metadata and search results
|
|
632
|
-
const result = response.response;
|
|
633
684
|
const candidates = result.candidates;
|
|
634
685
|
if (!candidates || candidates.length === 0) {
|
|
635
686
|
return {
|
|
@@ -638,33 +689,18 @@ export const directAgentTools = {
|
|
|
638
689
|
query,
|
|
639
690
|
};
|
|
640
691
|
}
|
|
641
|
-
|
|
642
|
-
|
|
692
|
+
// Extract raw search content. The aggregated `text` getter joins every
|
|
693
|
+
// text part, so it survives responses that lead with a non-text part.
|
|
694
|
+
const searchContent = result.text?.trim() || "";
|
|
695
|
+
if (!searchContent) {
|
|
643
696
|
return {
|
|
644
697
|
success: false,
|
|
645
698
|
error: "No search content found",
|
|
646
699
|
query,
|
|
647
700
|
};
|
|
648
701
|
}
|
|
649
|
-
// Extract raw search content
|
|
650
|
-
const searchContent = content.parts[0].text || "";
|
|
651
702
|
// Extract grounding sources if available
|
|
652
|
-
const
|
|
653
|
-
const searchResults = [];
|
|
654
|
-
if (groundingMetadata?.groundingChunks) {
|
|
655
|
-
for (const chunk of groundingMetadata.groundingChunks.slice(0, limitedResults)) {
|
|
656
|
-
if (chunk.web) {
|
|
657
|
-
searchResults.push({
|
|
658
|
-
title: chunk.web.title || "No title",
|
|
659
|
-
url: chunk.web.uri || "",
|
|
660
|
-
snippet: searchContent, // Use full content since maxWords already limits length
|
|
661
|
-
domain: chunk.web.uri
|
|
662
|
-
? new URL(chunk.web.uri).hostname
|
|
663
|
-
: "unknown",
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
}
|
|
703
|
+
const searchResults = buildWebsearchResults(candidates[0]?.groundingMetadata, searchContent, limitedResults);
|
|
668
704
|
// If no grounding metadata, create basic result structure
|
|
669
705
|
if (searchResults.length === 0) {
|
|
670
706
|
searchResults.push({
|
|
@@ -6,6 +6,8 @@ export declare function getGlobalInstallArgs(kind: GlobalInstallerKind, packageS
|
|
|
6
6
|
* Return whether a global package-manager failure is likely environmental and
|
|
7
7
|
* worth retrying. Configuration and permission failures deliberately return
|
|
8
8
|
* false so the updater does not repeatedly mutate a broken installation.
|
|
9
|
+
*
|
|
10
|
+
* @param error - The package-manager error, including any nested `cause` chain.
|
|
9
11
|
*/
|
|
10
12
|
export declare function isTransientInstallFailure(error: unknown): boolean;
|
|
11
13
|
/**
|
|
@@ -146,17 +146,25 @@ const TRANSIENT_INSTALL_FAILURE_CODES = new Set([
|
|
|
146
146
|
"EPIPE",
|
|
147
147
|
"ETIMEDOUT",
|
|
148
148
|
]);
|
|
149
|
+
const MAX_INSTALL_FAILURE_CAUSE_DEPTH = 10;
|
|
149
150
|
/**
|
|
150
151
|
* Return whether a global package-manager failure is likely environmental and
|
|
151
152
|
* worth retrying. Configuration and permission failures deliberately return
|
|
152
153
|
* false so the updater does not repeatedly mutate a broken installation.
|
|
154
|
+
*
|
|
155
|
+
* @param error - The package-manager error, including any nested `cause` chain.
|
|
153
156
|
*/
|
|
154
157
|
export function isTransientInstallFailure(error) {
|
|
155
158
|
let current = error;
|
|
156
|
-
|
|
159
|
+
const seen = new Set();
|
|
160
|
+
for (let depth = 0; depth < MAX_INSTALL_FAILURE_CAUSE_DEPTH && current; depth++) {
|
|
157
161
|
if (typeof current !== "object") {
|
|
158
162
|
return false;
|
|
159
163
|
}
|
|
164
|
+
if (seen.has(current)) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
seen.add(current);
|
|
160
168
|
const candidate = current;
|
|
161
169
|
if (typeof candidate.code === "string" &&
|
|
162
170
|
TRANSIENT_INSTALL_FAILURE_CODES.has(candidate.code)) {
|
|
@@ -424,10 +424,12 @@ export class RollingWorkerSupervisor {
|
|
|
424
424
|
if (this.active?.generation === worker.generation && !this.closed) {
|
|
425
425
|
this.active = null;
|
|
426
426
|
this.draining.set(worker.generation, worker);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
427
|
+
if (!lifecycle.observedExit) {
|
|
428
|
+
// The child may own a duplicate of an incompletely transferred socket.
|
|
429
|
+
// SIGKILL closes its descriptor without worker-side shutdown(2), after
|
|
430
|
+
// which the parent rejects its copy rather than attempting unsafe replay.
|
|
431
|
+
worker.handle.terminate("SIGKILL");
|
|
432
|
+
}
|
|
431
433
|
this.publishState();
|
|
432
434
|
}
|
|
433
435
|
this.rejectSocket(socket);
|
|
@@ -6,6 +6,8 @@ export declare function getGlobalInstallArgs(kind: GlobalInstallerKind, packageS
|
|
|
6
6
|
* Return whether a global package-manager failure is likely environmental and
|
|
7
7
|
* worth retrying. Configuration and permission failures deliberately return
|
|
8
8
|
* false so the updater does not repeatedly mutate a broken installation.
|
|
9
|
+
*
|
|
10
|
+
* @param error - The package-manager error, including any nested `cause` chain.
|
|
9
11
|
*/
|
|
10
12
|
export declare function isTransientInstallFailure(error: unknown): boolean;
|
|
11
13
|
/**
|
|
@@ -146,17 +146,25 @@ const TRANSIENT_INSTALL_FAILURE_CODES = new Set([
|
|
|
146
146
|
"EPIPE",
|
|
147
147
|
"ETIMEDOUT",
|
|
148
148
|
]);
|
|
149
|
+
const MAX_INSTALL_FAILURE_CAUSE_DEPTH = 10;
|
|
149
150
|
/**
|
|
150
151
|
* Return whether a global package-manager failure is likely environmental and
|
|
151
152
|
* worth retrying. Configuration and permission failures deliberately return
|
|
152
153
|
* false so the updater does not repeatedly mutate a broken installation.
|
|
154
|
+
*
|
|
155
|
+
* @param error - The package-manager error, including any nested `cause` chain.
|
|
153
156
|
*/
|
|
154
157
|
export function isTransientInstallFailure(error) {
|
|
155
158
|
let current = error;
|
|
156
|
-
|
|
159
|
+
const seen = new Set();
|
|
160
|
+
for (let depth = 0; depth < MAX_INSTALL_FAILURE_CAUSE_DEPTH && current; depth++) {
|
|
157
161
|
if (typeof current !== "object") {
|
|
158
162
|
return false;
|
|
159
163
|
}
|
|
164
|
+
if (seen.has(current)) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
seen.add(current);
|
|
160
168
|
const candidate = current;
|
|
161
169
|
if (typeof candidate.code === "string" &&
|
|
162
170
|
TRANSIENT_INSTALL_FAILURE_CODES.has(candidate.code)) {
|
|
@@ -424,10 +424,12 @@ export class RollingWorkerSupervisor {
|
|
|
424
424
|
if (this.active?.generation === worker.generation && !this.closed) {
|
|
425
425
|
this.active = null;
|
|
426
426
|
this.draining.set(worker.generation, worker);
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
427
|
+
if (!lifecycle.observedExit) {
|
|
428
|
+
// The child may own a duplicate of an incompletely transferred socket.
|
|
429
|
+
// SIGKILL closes its descriptor without worker-side shutdown(2), after
|
|
430
|
+
// which the parent rejects its copy rather than attempting unsafe replay.
|
|
431
|
+
worker.handle.terminate("SIGKILL");
|
|
432
|
+
}
|
|
431
433
|
this.publishState();
|
|
432
434
|
}
|
|
433
435
|
this.rejectSocket(socket);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.9.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": {
|
|
@@ -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": "",
|