@juspay/neurolink 12.9.5 → 12.9.6
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 +2 -2
- package/dist/browser/neurolink.min.js +364 -364
- package/dist/neurolink.d.ts +29 -1
- package/dist/neurolink.js +69 -1
- package/dist/types/mcp.d.ts +16 -0
- package/dist/utils/toolCallRepair.d.ts +42 -0
- package/dist/utils/toolCallRepair.js +78 -15
- package/package.json +3 -2
package/dist/neurolink.d.ts
CHANGED
|
@@ -1943,9 +1943,37 @@ export declare class NeuroLink {
|
|
|
1943
1943
|
* @param options - Execution options
|
|
1944
1944
|
* @returns Tool execution result
|
|
1945
1945
|
*/
|
|
1946
|
-
executeExternalMCPTool(serverId: string,
|
|
1946
|
+
executeExternalMCPTool(serverId: string, requestedToolName: string, parameters: JsonObject, options?: {
|
|
1947
1947
|
timeout?: number;
|
|
1948
1948
|
}): Promise<unknown>;
|
|
1949
|
+
/**
|
|
1950
|
+
* Resolve a tool name for a direct external MCP execution
|
|
1951
|
+
* (`executeExternalMCPTool`) against the server's currently discovered
|
|
1952
|
+
* tools.
|
|
1953
|
+
*
|
|
1954
|
+
* `experimental_repairToolCall` only runs inside the AI-SDK's own
|
|
1955
|
+
* streamText/generateText loop (see toolCallRepair.ts), so a near-miss
|
|
1956
|
+
* tool name reaching `executeExternalMCPTool` directly previously had no
|
|
1957
|
+
* recovery at all — just the generic `Tool 'x' not found for server 'y'`
|
|
1958
|
+
* `Error` that `ToolDiscoveryService.executeTool` throws deeper in the
|
|
1959
|
+
* stack. This reuses the same name-matching policy
|
|
1960
|
+
* (`resolveToolName`: case-insensitive exact → unambiguous substring →
|
|
1961
|
+
* Levenshtein) so a repair here is accepted under exactly the rules
|
|
1962
|
+
* already proven for the generation path.
|
|
1963
|
+
*
|
|
1964
|
+
* Exact match is a zero-risk fast path: it is returned unchanged before
|
|
1965
|
+
* any resolution attempt, so every existing caller that already sends a
|
|
1966
|
+
* valid name — including the AI-SDK path's `createExternalMCPTool`, which
|
|
1967
|
+
* always executes with a name it just discovered — sees no behaviour
|
|
1968
|
+
* change.
|
|
1969
|
+
*
|
|
1970
|
+
* Deliberately does NOT attempt a repair when the server is unknown or
|
|
1971
|
+
* not connected: `ExternalServerManager.executeTool` throws distinct,
|
|
1972
|
+
* more accurate errors for those states ("Server 'x' not found" /
|
|
1973
|
+
* "not in connected state"), and resolving against an empty tool list
|
|
1974
|
+
* here would replace those with a misleading "tool not found" instead.
|
|
1975
|
+
*/
|
|
1976
|
+
private resolveDirectMcpToolName;
|
|
1949
1977
|
/**
|
|
1950
1978
|
* Get all tools from external MCP servers
|
|
1951
1979
|
* @returns Array of external tool information
|
package/dist/neurolink.js
CHANGED
|
@@ -89,6 +89,7 @@ import { logger, mcpLogger } from "./utils/logger.js";
|
|
|
89
89
|
import { redactUrlCredentials, safeDebugSerialize, sanitizeRecord, stringifyContentSafe, } from "./utils/logSanitize.js";
|
|
90
90
|
import { extractMcpErrorText } from "./utils/mcpErrorText.js";
|
|
91
91
|
import { createCustomToolServerInfo, detectCategory, } from "./utils/mcpDefaults.js";
|
|
92
|
+
import { ExternalMcpToolNotFoundError, rankToolNameCandidates, resolveToolName, } from "./utils/toolCallRepair.js";
|
|
92
93
|
import { resolveModel } from "./utils/modelAliasResolver.js";
|
|
93
94
|
// Import orchestration components
|
|
94
95
|
import { ModelRouter } from "./utils/modelRouter.js";
|
|
@@ -11732,8 +11733,16 @@ Current user's request: ${currentInput}`;
|
|
|
11732
11733
|
* @param options - Execution options
|
|
11733
11734
|
* @returns Tool execution result
|
|
11734
11735
|
*/
|
|
11735
|
-
async executeExternalMCPTool(serverId,
|
|
11736
|
+
async executeExternalMCPTool(serverId, requestedToolName, parameters, options) {
|
|
11737
|
+
// Falls back to the requested name so the catch block below still has
|
|
11738
|
+
// something meaningful to log if resolution itself is what throws.
|
|
11739
|
+
let toolName = requestedToolName;
|
|
11736
11740
|
try {
|
|
11741
|
+
// Direct-boundary name repair (see resolveDirectMcpToolName): an exact
|
|
11742
|
+
// match returns requestedToolName unchanged, so every existing caller
|
|
11743
|
+
// — including the AI-SDK generation path's createExternalMCPTool,
|
|
11744
|
+
// which always calls with an already-discovered name — is unaffected.
|
|
11745
|
+
toolName = this.resolveDirectMcpToolName(serverId, requestedToolName);
|
|
11737
11746
|
mcpLogger.debug(`[NeuroLink] Executing external MCP tool: ${toolName} on ${serverId}`);
|
|
11738
11747
|
// BZ-664: Check existing ToolResultCache before executing to avoid
|
|
11739
11748
|
// duplicate identical calls within the same session.
|
|
@@ -11803,6 +11812,65 @@ Current user's request: ${currentInput}`;
|
|
|
11803
11812
|
throw error;
|
|
11804
11813
|
}
|
|
11805
11814
|
}
|
|
11815
|
+
/**
|
|
11816
|
+
* Resolve a tool name for a direct external MCP execution
|
|
11817
|
+
* (`executeExternalMCPTool`) against the server's currently discovered
|
|
11818
|
+
* tools.
|
|
11819
|
+
*
|
|
11820
|
+
* `experimental_repairToolCall` only runs inside the AI-SDK's own
|
|
11821
|
+
* streamText/generateText loop (see toolCallRepair.ts), so a near-miss
|
|
11822
|
+
* tool name reaching `executeExternalMCPTool` directly previously had no
|
|
11823
|
+
* recovery at all — just the generic `Tool 'x' not found for server 'y'`
|
|
11824
|
+
* `Error` that `ToolDiscoveryService.executeTool` throws deeper in the
|
|
11825
|
+
* stack. This reuses the same name-matching policy
|
|
11826
|
+
* (`resolveToolName`: case-insensitive exact → unambiguous substring →
|
|
11827
|
+
* Levenshtein) so a repair here is accepted under exactly the rules
|
|
11828
|
+
* already proven for the generation path.
|
|
11829
|
+
*
|
|
11830
|
+
* Exact match is a zero-risk fast path: it is returned unchanged before
|
|
11831
|
+
* any resolution attempt, so every existing caller that already sends a
|
|
11832
|
+
* valid name — including the AI-SDK path's `createExternalMCPTool`, which
|
|
11833
|
+
* always executes with a name it just discovered — sees no behaviour
|
|
11834
|
+
* change.
|
|
11835
|
+
*
|
|
11836
|
+
* Deliberately does NOT attempt a repair when the server is unknown or
|
|
11837
|
+
* not connected: `ExternalServerManager.executeTool` throws distinct,
|
|
11838
|
+
* more accurate errors for those states ("Server 'x' not found" /
|
|
11839
|
+
* "not in connected state"), and resolving against an empty tool list
|
|
11840
|
+
* here would replace those with a misleading "tool not found" instead.
|
|
11841
|
+
*/
|
|
11842
|
+
resolveDirectMcpToolName(serverId, requestedName) {
|
|
11843
|
+
const server = this.getExternalMCPServer(serverId);
|
|
11844
|
+
if (!server || server.status !== "connected" || !server.client) {
|
|
11845
|
+
return requestedName;
|
|
11846
|
+
}
|
|
11847
|
+
const availableNames = this.getExternalMCPServerTools(serverId).map((tool) => tool.name);
|
|
11848
|
+
if (availableNames.includes(requestedName)) {
|
|
11849
|
+
return requestedName;
|
|
11850
|
+
}
|
|
11851
|
+
const resolution = resolveToolName(requestedName, availableNames);
|
|
11852
|
+
if (!resolution) {
|
|
11853
|
+
throw new ExternalMcpToolNotFoundError(requestedName, serverId, rankToolNameCandidates(requestedName, availableNames));
|
|
11854
|
+
}
|
|
11855
|
+
// Recorded on a short-lived span rather than the method's return value:
|
|
11856
|
+
// executeExternalMCPTool returns the raw upstream tool result verbatim
|
|
11857
|
+
// (widely consumed as-is, e.g. by createExternalMCPTool's execute()),
|
|
11858
|
+
// so wrapping it to carry resolution metadata would be a breaking
|
|
11859
|
+
// change for every existing direct caller.
|
|
11860
|
+
tracers.mcp.startActiveSpan("neurolink.mcp.toolNameRepair", {
|
|
11861
|
+
attributes: {
|
|
11862
|
+
"mcp.server_id": serverId,
|
|
11863
|
+
"mcp.tool_name.requested": requestedName,
|
|
11864
|
+
"mcp.tool_name.resolved": resolution.name,
|
|
11865
|
+
"mcp.tool_name.repair_strategy": resolution.strategy,
|
|
11866
|
+
...(resolution.score !== undefined
|
|
11867
|
+
? { "mcp.tool_name.repair_score": resolution.score }
|
|
11868
|
+
: {}),
|
|
11869
|
+
},
|
|
11870
|
+
}, (span) => span.end());
|
|
11871
|
+
mcpLogger.info(`[NeuroLink] Repaired external MCP tool name at direct execution boundary: "${requestedName}" → "${resolution.name}" (${resolution.strategy}) on server '${serverId}'`);
|
|
11872
|
+
return resolution.name;
|
|
11873
|
+
}
|
|
11806
11874
|
/**
|
|
11807
11875
|
* Get all tools from external MCP servers
|
|
11808
11876
|
* @returns Array of external tool information
|
package/dist/types/mcp.d.ts
CHANGED
|
@@ -422,6 +422,22 @@ export type ToolDiscoveryResult = {
|
|
|
422
422
|
/** Server ID */
|
|
423
423
|
serverId: string;
|
|
424
424
|
};
|
|
425
|
+
/**
|
|
426
|
+
* Outcome of matching a possibly-misspelled tool name against a list of
|
|
427
|
+
* available tool names (see `resolveToolName` in
|
|
428
|
+
* src/lib/utils/toolCallRepair.ts). Shared between the AI-SDK generation-path
|
|
429
|
+
* repair (`experimental_repairToolCall`) and direct MCP execution boundaries
|
|
430
|
+
* (`NeuroLink.executeExternalMCPTool`) so both recover from the same class of
|
|
431
|
+
* near-miss the same way.
|
|
432
|
+
*/
|
|
433
|
+
export type ToolNameResolution = {
|
|
434
|
+
/** The resolved, available tool name. */
|
|
435
|
+
name: string;
|
|
436
|
+
/** Which strategy produced the match, in the order they are attempted. */
|
|
437
|
+
strategy: "case" | "substring" | "levenshtein";
|
|
438
|
+
/** Normalized Levenshtein distance (0–1) — only set when strategy is "levenshtein". */
|
|
439
|
+
score?: number;
|
|
440
|
+
};
|
|
425
441
|
/**
|
|
426
442
|
* External MCP tool execution options
|
|
427
443
|
* Moved from src/lib/mcp/toolDiscoveryService.ts
|
|
@@ -1,9 +1,51 @@
|
|
|
1
1
|
import type { ToolCallRepairFunction, ToolSet } from "../types/index.js";
|
|
2
|
+
import type { ToolNameResolution } from "../types/index.js";
|
|
2
3
|
/**
|
|
3
4
|
* Create an `experimental_repairToolCall` handler for streamText/generateText.
|
|
4
5
|
* Fully dynamic — reads the tool schema at repair time, no configuration needed.
|
|
5
6
|
*/
|
|
6
7
|
export declare function createToolCallRepair(): ToolCallRepairFunction<ToolSet>;
|
|
8
|
+
/**
|
|
9
|
+
* Match a possibly-misspelled tool name against a list of available tool
|
|
10
|
+
* names. Strategies (in order): case-insensitive exact → unambiguous
|
|
11
|
+
* substring → Levenshtein.
|
|
12
|
+
*
|
|
13
|
+
* Pulled out of `repairToolName` so the same matching policy can be reused
|
|
14
|
+
* outside the AI-SDK generation loop — `experimental_repairToolCall` only
|
|
15
|
+
* runs inside `streamText`/`generateText`, so a name typo at a direct MCP
|
|
16
|
+
* execution boundary (`NeuroLink.executeExternalMCPTool`) previously had no
|
|
17
|
+
* recovery at all. This function is pure name-matching: no `LanguageModelV3ToolCall`,
|
|
18
|
+
* no logging, so callers with a different call shape can reuse it directly.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveToolName(calledName: string, availableTools: string[]): ToolNameResolution | null;
|
|
21
|
+
/**
|
|
22
|
+
* Rank every available tool name by similarity to `calledName` (ascending
|
|
23
|
+
* normalized Levenshtein distance) and return the closest `limit`.
|
|
24
|
+
*
|
|
25
|
+
* Used to build the candidate list on `ExternalMcpToolNotFoundError` when
|
|
26
|
+
* `resolveToolName` found no unambiguous match — unlike `resolveToolName`,
|
|
27
|
+
* this makes no accept/reject judgment, it just orders what is available so
|
|
28
|
+
* a caller (human or AI) can pick the right name themselves.
|
|
29
|
+
*/
|
|
30
|
+
export declare function rankToolNameCandidates(calledName: string, availableTools: string[], limit?: number): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Thrown at a direct MCP execution boundary (`NeuroLink.executeExternalMCPTool`)
|
|
33
|
+
* when `resolveToolName` cannot find an unambiguous match for a requested
|
|
34
|
+
* tool name against a server's discovered tools. Distinct from the plain
|
|
35
|
+
* `Error` that `ToolDiscoveryService.executeTool` throws deeper in the stack
|
|
36
|
+
* for the same condition, so callers can distinguish "no match — here are
|
|
37
|
+
* the closest names" from every other execution failure programmatically,
|
|
38
|
+
* instead of parsing a message string.
|
|
39
|
+
*/
|
|
40
|
+
export declare class ExternalMcpToolNotFoundError extends Error {
|
|
41
|
+
/** The tool name that was requested and could not be resolved. */
|
|
42
|
+
readonly requestedName: string;
|
|
43
|
+
/** The server the tool was requested against. */
|
|
44
|
+
readonly serverId: string;
|
|
45
|
+
/** Closest available tool names on that server, capped (see `rankToolNameCandidates`). */
|
|
46
|
+
readonly candidates: string[];
|
|
47
|
+
constructor(requestedName: string, serverId: string, candidates: string[]);
|
|
48
|
+
}
|
|
7
49
|
/**
|
|
8
50
|
* Coerce a value to match the expected schema type.
|
|
9
51
|
* Handles: string→number, JSON string→object, JSON string→array, value→[value].
|
|
@@ -25,31 +25,36 @@ export function createToolCallRepair() {
|
|
|
25
25
|
}
|
|
26
26
|
// ─── Tool Name Repair ──────────────────────────────────────────────
|
|
27
27
|
/**
|
|
28
|
-
*
|
|
29
|
-
* Strategies (in order): case-insensitive exact →
|
|
28
|
+
* Match a possibly-misspelled tool name against a list of available tool
|
|
29
|
+
* names. Strategies (in order): case-insensitive exact → unambiguous
|
|
30
|
+
* substring → Levenshtein.
|
|
31
|
+
*
|
|
32
|
+
* Pulled out of `repairToolName` so the same matching policy can be reused
|
|
33
|
+
* outside the AI-SDK generation loop — `experimental_repairToolCall` only
|
|
34
|
+
* runs inside `streamText`/`generateText`, so a name typo at a direct MCP
|
|
35
|
+
* execution boundary (`NeuroLink.executeExternalMCPTool`) previously had no
|
|
36
|
+
* recovery at all. This function is pure name-matching: no `LanguageModelV3ToolCall`,
|
|
37
|
+
* no logging, so callers with a different call shape can reuse it directly.
|
|
30
38
|
*/
|
|
31
|
-
function
|
|
32
|
-
const called = toolCall.toolName;
|
|
39
|
+
export function resolveToolName(calledName, availableTools) {
|
|
33
40
|
// Guard: empty or whitespace-only tool name cannot be meaningfully repaired
|
|
34
|
-
if (!
|
|
41
|
+
if (!calledName || calledName.trim().length === 0) {
|
|
35
42
|
return null;
|
|
36
43
|
}
|
|
37
44
|
// 1. Case-insensitive exact match
|
|
38
|
-
const ciMatch = availableTools.find((t) => t.toLowerCase() ===
|
|
45
|
+
const ciMatch = availableTools.find((t) => t.toLowerCase() === calledName.toLowerCase());
|
|
39
46
|
if (ciMatch) {
|
|
40
|
-
|
|
41
|
-
return { ...toolCall, toolName: ciMatch };
|
|
47
|
+
return { name: ciMatch, strategy: "case" };
|
|
42
48
|
}
|
|
43
49
|
// 2. Substring match: "search_file" is substring of "search_files" or vice versa.
|
|
44
50
|
// Only accept when exactly one tool matches to avoid ambiguous repairs.
|
|
45
|
-
const calledLower =
|
|
51
|
+
const calledLower = calledName.toLowerCase();
|
|
46
52
|
const subCandidates = availableTools.filter((t) => {
|
|
47
53
|
const tLower = t.toLowerCase();
|
|
48
54
|
return tLower.includes(calledLower) || calledLower.includes(tLower);
|
|
49
55
|
});
|
|
50
56
|
if (subCandidates.length === 1) {
|
|
51
|
-
|
|
52
|
-
return { ...toolCall, toolName: subCandidates[0] };
|
|
57
|
+
return { name: subCandidates[0], strategy: "substring" };
|
|
53
58
|
}
|
|
54
59
|
// 3. Levenshtein distance — accept if normalized distance < 0.3
|
|
55
60
|
// Compare by normalized score (not raw edits) so length differences don't skew selection.
|
|
@@ -57,7 +62,7 @@ function repairToolName(toolCall, availableTools) {
|
|
|
57
62
|
let bestNormalized = Infinity;
|
|
58
63
|
for (const t of availableTools) {
|
|
59
64
|
const dist = levenshtein(calledLower, t.toLowerCase());
|
|
60
|
-
const maxLen = Math.max(
|
|
65
|
+
const maxLen = Math.max(calledName.length, t.length);
|
|
61
66
|
const normalized = maxLen === 0 ? 0 : dist / maxLen;
|
|
62
67
|
if (normalized < 0.3 && normalized < bestNormalized) {
|
|
63
68
|
bestNormalized = normalized;
|
|
@@ -65,12 +70,70 @@ function repairToolName(toolCall, availableTools) {
|
|
|
65
70
|
}
|
|
66
71
|
}
|
|
67
72
|
if (bestMatch) {
|
|
68
|
-
|
|
69
|
-
return { ...toolCall, toolName: bestMatch };
|
|
73
|
+
return { name: bestMatch, strategy: "levenshtein", score: bestNormalized };
|
|
70
74
|
}
|
|
71
|
-
logger.debug(`[ToolCallRepair] Could not repair tool name "${called}". Available: [${availableTools.join(", ")}]`);
|
|
72
75
|
return null;
|
|
73
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Rank every available tool name by similarity to `calledName` (ascending
|
|
79
|
+
* normalized Levenshtein distance) and return the closest `limit`.
|
|
80
|
+
*
|
|
81
|
+
* Used to build the candidate list on `ExternalMcpToolNotFoundError` when
|
|
82
|
+
* `resolveToolName` found no unambiguous match — unlike `resolveToolName`,
|
|
83
|
+
* this makes no accept/reject judgment, it just orders what is available so
|
|
84
|
+
* a caller (human or AI) can pick the right name themselves.
|
|
85
|
+
*/
|
|
86
|
+
export function rankToolNameCandidates(calledName, availableTools, limit = 5) {
|
|
87
|
+
const calledLower = calledName.toLowerCase();
|
|
88
|
+
return [...availableTools]
|
|
89
|
+
.sort((a, b) => levenshtein(calledLower, a.toLowerCase()) -
|
|
90
|
+
levenshtein(calledLower, b.toLowerCase()))
|
|
91
|
+
.slice(0, limit);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Thrown at a direct MCP execution boundary (`NeuroLink.executeExternalMCPTool`)
|
|
95
|
+
* when `resolveToolName` cannot find an unambiguous match for a requested
|
|
96
|
+
* tool name against a server's discovered tools. Distinct from the plain
|
|
97
|
+
* `Error` that `ToolDiscoveryService.executeTool` throws deeper in the stack
|
|
98
|
+
* for the same condition, so callers can distinguish "no match — here are
|
|
99
|
+
* the closest names" from every other execution failure programmatically,
|
|
100
|
+
* instead of parsing a message string.
|
|
101
|
+
*/
|
|
102
|
+
export class ExternalMcpToolNotFoundError extends Error {
|
|
103
|
+
/** The tool name that was requested and could not be resolved. */
|
|
104
|
+
requestedName;
|
|
105
|
+
/** The server the tool was requested against. */
|
|
106
|
+
serverId;
|
|
107
|
+
/** Closest available tool names on that server, capped (see `rankToolNameCandidates`). */
|
|
108
|
+
candidates;
|
|
109
|
+
constructor(requestedName, serverId, candidates) {
|
|
110
|
+
const candidateList = candidates.length > 0 ? candidates.join(", ") : "(none registered)";
|
|
111
|
+
super(`Tool '${requestedName}' not found for server '${serverId}'. Closest available: ${candidateList}`);
|
|
112
|
+
this.name = "ExternalMcpToolNotFoundError";
|
|
113
|
+
this.requestedName = requestedName;
|
|
114
|
+
this.serverId = serverId;
|
|
115
|
+
this.candidates = candidates;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Attempt to match a wrong tool name against available tool names and
|
|
120
|
+
* produce a repaired `LanguageModelV3ToolCall` for the AI-SDK generation
|
|
121
|
+
* path. Thin wrapper around `resolveToolName` that restores this function's
|
|
122
|
+
* original debug-log wording so generation-path behaviour is unchanged.
|
|
123
|
+
*/
|
|
124
|
+
function repairToolName(toolCall, availableTools) {
|
|
125
|
+
const called = toolCall.toolName;
|
|
126
|
+
const resolution = resolveToolName(called, availableTools);
|
|
127
|
+
if (!resolution) {
|
|
128
|
+
logger.debug(`[ToolCallRepair] Could not repair tool name "${called}". Available: [${availableTools.join(", ")}]`);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const label = resolution.strategy === "levenshtein"
|
|
132
|
+
? `levenshtein ${resolution.score.toFixed(2)}`
|
|
133
|
+
: resolution.strategy;
|
|
134
|
+
logger.debug(`[ToolCallRepair] Name repair (${label}): "${called}" → "${resolution.name}"`);
|
|
135
|
+
return { ...toolCall, toolName: resolution.name };
|
|
136
|
+
}
|
|
74
137
|
// ─── Tool Input Repair ─────────────────────────────────────────────
|
|
75
138
|
/**
|
|
76
139
|
* Attempt to repair wrong parameter names and types using the JSON schema.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "12.9.
|
|
3
|
+
"version": "12.9.6",
|
|
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": {
|
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
"test:mcp:sdk": "pnpm exec tsx test/continuous-test-suite-mcp-sdk.ts",
|
|
87
87
|
"test:mcp:cli": "pnpm exec tsx test/continuous-test-suite-mcp-cli.ts",
|
|
88
88
|
"test:mcp:stdio-lifecycle": "pnpm exec tsx test/continuous-test-suite-mcp-stdio-lifecycle.ts",
|
|
89
|
+
"test:mcp-direct-name-repair": "pnpm exec tsx test/continuous-test-suite-mcp-direct-name-repair.ts",
|
|
89
90
|
"test:mcp:full": "pnpm run test:mcp:infra && pnpm run test:mcp:spans && pnpm run test:mcp:stdio-lifecycle && pnpm run test:mcp:sdk && pnpm run test:mcp:cli && pnpm run test:mcp:http",
|
|
90
91
|
"test:media": "pnpm exec tsx test/continuous-test-suite-media-gen.ts",
|
|
91
92
|
"test:media-registry-collisions": "pnpm exec tsx test/continuous-test-suite-media-registry-collisions.ts",
|
|
@@ -154,7 +155,7 @@
|
|
|
154
155
|
"// CI tier — fast, no live AI calls, safe for every commit (test:unit; also see the separate provider-safety-net CI job, which runs build + test:providers-mocked + test:provider-structure + test:error-classifier-contract on every PR)": "",
|
|
155
156
|
"test:tool-routing": "pnpm exec tsx test/continuous-test-suite-tool-routing.ts",
|
|
156
157
|
"test:tool-routing-semantic": "pnpm exec tsx test/continuous-test-suite-tool-routing-semantic.ts",
|
|
157
|
-
"test:unit": "pnpm run test:bugfixes && pnpm run test:mcp:infra && pnpm run test:mcp:spans && pnpm run test:tool-routing && pnpm run test:tool-routing-cli && pnpm run test:tool-dedup && pnpm run test:model-pool && pnpm run test:classifier-router && pnpm run test:tool-routing-semantic && pnpm run test:mcp-result-cache && pnpm run test:model-not-found-retryable && pnpm run test:archive:security && pnpm run test:office:security && pnpm run test:vector-chroma && pnpm run test:vector-pgvector && pnpm run test:vector-pinecone && pnpm run test:provider-wiring && pnpm run test:docs-mcp",
|
|
158
|
+
"test:unit": "pnpm run test:bugfixes && pnpm run test:mcp:infra && pnpm run test:mcp:spans && pnpm run test:tool-routing && pnpm run test:tool-routing-cli && pnpm run test:tool-dedup && pnpm run test:model-pool && pnpm run test:classifier-router && pnpm run test:tool-routing-semantic && pnpm run test:mcp-result-cache && pnpm run test:mcp-direct-name-repair && pnpm run test:model-not-found-retryable && pnpm run test:archive:security && pnpm run test:office:security && pnpm run test:vector-chroma && pnpm run test:vector-pgvector && pnpm run test:vector-pinecone && pnpm run test:provider-wiring && pnpm run test:docs-mcp",
|
|
158
159
|
"// 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; test:matrix, a different suite covering the full provider capability matrix, runs nightly via .github/workflows/live-matrix.yml — test:providers itself is still only wired into test:live, not any GitHub Actions workflow)": "",
|
|
159
160
|
"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",
|
|
160
161
|
"// CI tier — product output (image/video/TTS/PPT) — costs $$ per run (not wired into any GitHub Actions workflow as of this comment; run manually or add to live-matrix.yml if nightly coverage is needed)": "",
|