@juspay/neurolink 13.8.0 → 13.8.2
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 -6
- package/dist/browser/neurolink.min.js +404 -404
- package/dist/core/redisConversationMemoryManager.js +0 -3
- package/dist/mcp/externalServerManager.js +4 -1
- package/dist/mcp/mcpClientFactory.d.ts +6 -0
- package/dist/mcp/mcpClientFactory.js +44 -0
- package/dist/neurolink.js +9 -2
- package/package.json +1 -1
|
@@ -539,9 +539,6 @@ export class RedisConversationMemoryManager {
|
|
|
539
539
|
messageCount: conversation.messages.length,
|
|
540
540
|
});
|
|
541
541
|
}
|
|
542
|
-
if (this.redisConfig.ttl > 0) {
|
|
543
|
-
await this.redisClient.expire(redisKey, this.redisConfig.ttl);
|
|
544
|
-
}
|
|
545
542
|
if (options.userId) {
|
|
546
543
|
await this.addUserSession(options.userId, options.sessionId);
|
|
547
544
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { EventEmitter } from "events";
|
|
10
10
|
import { mcpLogger } from "../utils/logger.js";
|
|
11
|
-
import { MCPClientFactory } from "./mcpClientFactory.js";
|
|
11
|
+
import { MCPClientFactory, terminateStartingStdioServers, } from "./mcpClientFactory.js";
|
|
12
12
|
import { ToolDiscoveryService } from "./toolDiscoveryService.js";
|
|
13
13
|
import { toolRegistry } from "./toolRegistry.js";
|
|
14
14
|
import { HITLUserRejectedError, HITLTimeoutError } from "../hitl/hitlErrors.js";
|
|
@@ -372,6 +372,9 @@ const shutdownOnSignal = (signal) => {
|
|
|
372
372
|
// re-raise and nowhere else.
|
|
373
373
|
if (!hadOtherListeners) {
|
|
374
374
|
process.removeListener(signal, shutdownOnSignal);
|
|
375
|
+
// Dying of a signal runs no `exit` handler, and the cleanup above cannot
|
|
376
|
+
// reach a server whose handshake is still pending.
|
|
377
|
+
terminateStartingStdioServers();
|
|
375
378
|
process.kill(process.pid, signal);
|
|
376
379
|
}
|
|
377
380
|
});
|
|
@@ -9,6 +9,12 @@ import type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
|
9
9
|
import type { ClientCapabilities } from "@modelcontextprotocol/sdk/types.js";
|
|
10
10
|
import type { ChildProcess } from "child_process";
|
|
11
11
|
import type { MCPTransportType, MCPServerInfo, MCPClientResult } from "../types/index.js";
|
|
12
|
+
/**
|
|
13
|
+
* Synchronous on purpose: it is the one thing that can run inside the
|
|
14
|
+
* `exit` event, and SIGTERM is delivered by the kernel even though this
|
|
15
|
+
* process is already on its way out.
|
|
16
|
+
*/
|
|
17
|
+
export declare const terminateStartingStdioServers: () => void;
|
|
12
18
|
/**
|
|
13
19
|
* MCPClientFactory
|
|
14
20
|
* Factory class for creating MCP clients with different transports
|
|
@@ -62,6 +62,48 @@ class StderrTail {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
const stderrTails = new WeakMap();
|
|
65
|
+
/**
|
|
66
|
+
* Stdio servers that have been spawned but have not yet answered `initialize`.
|
|
67
|
+
*
|
|
68
|
+
* Nothing that cleans up at exit can reach one: the manager learns of a client
|
|
69
|
+
* and its transport only when `connect()` returns, and `process.exit()` runs
|
|
70
|
+
* no async handler anyway. It is also the state a server is least likely to
|
|
71
|
+
* notice its host going away, because `npx -y <pkg>` does not read its stdin
|
|
72
|
+
* until the package has downloaded. Once a server has answered it is an
|
|
73
|
+
* ordinary MCP server again and ends when its stdin closes, so it leaves this
|
|
74
|
+
* set and the shutdown paths that already exist keep ownership of it.
|
|
75
|
+
*/
|
|
76
|
+
const startingStdioTransports = new Set();
|
|
77
|
+
let startingStdioExitHookInstalled = false;
|
|
78
|
+
/**
|
|
79
|
+
* Synchronous on purpose: it is the one thing that can run inside the
|
|
80
|
+
* `exit` event, and SIGTERM is delivered by the kernel even though this
|
|
81
|
+
* process is already on its way out.
|
|
82
|
+
*/
|
|
83
|
+
export const terminateStartingStdioServers = () => {
|
|
84
|
+
for (const transport of startingStdioTransports) {
|
|
85
|
+
if ("pid" in transport && typeof transport.pid === "number") {
|
|
86
|
+
try {
|
|
87
|
+
process.kill(transport.pid, "SIGTERM");
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Already gone.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const trackStartingStdioTransport = (transport) => {
|
|
96
|
+
if (!startingStdioExitHookInstalled) {
|
|
97
|
+
startingStdioExitHookInstalled = true;
|
|
98
|
+
process.on("exit", terminateStartingStdioServers);
|
|
99
|
+
}
|
|
100
|
+
startingStdioTransports.add(transport);
|
|
101
|
+
// Client.connect() chains an onclose that is already set rather than
|
|
102
|
+
// replacing it, and a spawn that fails still closes the transport.
|
|
103
|
+
transport.onclose = () => {
|
|
104
|
+
startingStdioTransports.delete(transport);
|
|
105
|
+
};
|
|
106
|
+
};
|
|
65
107
|
/**
|
|
66
108
|
* MCPClientFactory
|
|
67
109
|
* Factory class for creating MCP clients with different transports
|
|
@@ -223,6 +265,7 @@ export class MCPClientFactory {
|
|
|
223
265
|
}
|
|
224
266
|
// Connect with timeout
|
|
225
267
|
await this.raceWithTimeout(client.connect(transport, { timeout }), timeout, `Client connection timeout for ${config.id}`);
|
|
268
|
+
startingStdioTransports.delete(transport);
|
|
226
269
|
// Perform handshake to get server capabilities
|
|
227
270
|
const serverCapabilities = await this.performHandshake(client, timeout);
|
|
228
271
|
mcpLogger.debug(`[MCPClientFactory] Handshake completed for ${config.id}`, {
|
|
@@ -318,6 +361,7 @@ export class MCPClientFactory {
|
|
|
318
361
|
cwd: config.cwd,
|
|
319
362
|
stderr: "pipe",
|
|
320
363
|
});
|
|
364
|
+
trackStartingStdioTransport(transport);
|
|
321
365
|
const tail = new StderrTail();
|
|
322
366
|
stderrTails.set(transport, tail);
|
|
323
367
|
transport.stderr?.on("data", (chunk) => {
|
package/dist/neurolink.js
CHANGED
|
@@ -8993,8 +8993,6 @@ Current user's request: ${currentInput}`;
|
|
|
8993
8993
|
async prepareStreamOptions(options, streamId, startTime, hrTimeStart) {
|
|
8994
8994
|
// Initialize conversation memory if needed (for lazy loading)
|
|
8995
8995
|
await this.initializeConversationMemoryForGeneration(streamId, startTime, hrTimeStart);
|
|
8996
|
-
// Initialize MCP
|
|
8997
|
-
await this.initializeMCP();
|
|
8998
8996
|
// Memory retrieval
|
|
8999
8997
|
if (this.shouldReadMemory(options.memory, options.context?.userId) &&
|
|
9000
8998
|
options.context?.userId) {
|
|
@@ -9042,6 +9040,15 @@ Current user's request: ${currentInput}`;
|
|
|
9042
9040
|
}
|
|
9043
9041
|
// Auto-disable tools for Ollama models that don't support them
|
|
9044
9042
|
await this.autoDisableOllamaStreamTools(options);
|
|
9043
|
+
// generate() skips MCP when tools are disabled, so stream() must too:
|
|
9044
|
+
// initialization loads the working directory's .mcp-config.json and waits
|
|
9045
|
+
// for every stdio server it names before the request is sent, so an
|
|
9046
|
+
// `npx -y …` entry on a slow npm registry stalls a stream that never
|
|
9047
|
+
// needed a tool. Decided after the Ollama check above, which can turn
|
|
9048
|
+
// tools off. Providers register themselves in AIProviderFactory.
|
|
9049
|
+
if (!options.disableTools) {
|
|
9050
|
+
await this.initializeMCP();
|
|
9051
|
+
}
|
|
9045
9052
|
// RAG Integration: If rag config is provided, prepare the RAG search tool
|
|
9046
9053
|
if (options.rag?.files?.length) {
|
|
9047
9054
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "13.8.
|
|
3
|
+
"version": "13.8.2",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|