@juspay/neurolink 3.0.1 → 4.1.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 +66 -6
- package/README.md +318 -27
- package/dist/agent/direct-tools.d.ts +6 -6
- package/dist/chat/client-utils.d.ts +92 -0
- package/dist/chat/client-utils.js +298 -0
- package/dist/chat/index.d.ts +27 -0
- package/dist/chat/index.js +41 -0
- package/dist/chat/session-storage.d.ts +77 -0
- package/dist/chat/session-storage.js +233 -0
- package/dist/chat/session.d.ts +95 -0
- package/dist/chat/session.js +257 -0
- package/dist/chat/sse-handler.d.ts +49 -0
- package/dist/chat/sse-handler.js +266 -0
- package/dist/chat/types.d.ts +73 -0
- package/dist/chat/types.js +5 -0
- package/dist/chat/websocket-chat-handler.d.ts +36 -0
- package/dist/chat/websocket-chat-handler.js +262 -0
- package/dist/cli/commands/config.js +12 -12
- package/dist/cli/commands/mcp.js +3 -4
- package/dist/cli/index.d.ts +0 -7
- package/dist/cli/index.js +247 -28
- package/dist/config/configManager.d.ts +60 -0
- package/dist/config/configManager.js +300 -0
- package/dist/config/types.d.ts +136 -0
- package/dist/config/types.js +43 -0
- package/dist/core/analytics.d.ts +23 -0
- package/dist/core/analytics.js +131 -0
- package/dist/core/constants.d.ts +41 -0
- package/dist/core/constants.js +50 -0
- package/dist/core/defaults.d.ts +18 -0
- package/dist/core/defaults.js +29 -0
- package/dist/core/evaluation-config.d.ts +29 -0
- package/dist/core/evaluation-config.js +144 -0
- package/dist/core/evaluation-providers.d.ts +30 -0
- package/dist/core/evaluation-providers.js +187 -0
- package/dist/core/evaluation.d.ts +117 -0
- package/dist/core/evaluation.js +528 -0
- package/dist/core/factory.js +33 -25
- package/dist/core/types.d.ts +165 -6
- package/dist/core/types.js +3 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +25 -4
- package/dist/lib/agent/direct-tools.d.ts +6 -6
- package/dist/lib/chat/client-utils.d.ts +92 -0
- package/dist/lib/chat/client-utils.js +298 -0
- package/dist/lib/chat/index.d.ts +27 -0
- package/dist/lib/chat/index.js +41 -0
- package/dist/lib/chat/session-storage.d.ts +77 -0
- package/dist/lib/chat/session-storage.js +233 -0
- package/dist/lib/chat/session.d.ts +95 -0
- package/dist/lib/chat/session.js +257 -0
- package/dist/lib/chat/sse-handler.d.ts +49 -0
- package/dist/lib/chat/sse-handler.js +266 -0
- package/dist/lib/chat/types.d.ts +73 -0
- package/dist/lib/chat/types.js +5 -0
- package/dist/lib/chat/websocket-chat-handler.d.ts +36 -0
- package/dist/lib/chat/websocket-chat-handler.js +262 -0
- package/dist/lib/config/configManager.d.ts +60 -0
- package/dist/lib/config/configManager.js +300 -0
- package/dist/lib/config/types.d.ts +136 -0
- package/dist/lib/config/types.js +43 -0
- package/dist/lib/core/analytics.d.ts +23 -0
- package/dist/lib/core/analytics.js +131 -0
- package/dist/lib/core/constants.d.ts +41 -0
- package/dist/lib/core/constants.js +50 -0
- package/dist/lib/core/defaults.d.ts +18 -0
- package/dist/lib/core/defaults.js +29 -0
- package/dist/lib/core/evaluation-config.d.ts +29 -0
- package/dist/lib/core/evaluation-config.js +144 -0
- package/dist/lib/core/evaluation-providers.d.ts +30 -0
- package/dist/lib/core/evaluation-providers.js +187 -0
- package/dist/lib/core/evaluation.d.ts +117 -0
- package/dist/lib/core/evaluation.js +528 -0
- package/dist/lib/core/factory.js +33 -26
- package/dist/lib/core/types.d.ts +165 -6
- package/dist/lib/core/types.js +3 -4
- package/dist/lib/index.d.ts +9 -4
- package/dist/lib/index.js +25 -4
- package/dist/lib/mcp/contracts/mcpContract.d.ts +118 -0
- package/dist/lib/mcp/contracts/mcpContract.js +5 -0
- package/dist/lib/mcp/dynamic-chain-executor.d.ts +201 -0
- package/dist/lib/mcp/dynamic-chain-executor.js +489 -0
- package/dist/lib/mcp/dynamic-orchestrator.d.ts +109 -0
- package/dist/lib/mcp/dynamic-orchestrator.js +351 -0
- package/dist/lib/mcp/error-manager.d.ts +254 -0
- package/dist/lib/mcp/error-manager.js +501 -0
- package/dist/lib/mcp/error-recovery.d.ts +158 -0
- package/dist/lib/mcp/error-recovery.js +405 -0
- package/dist/lib/mcp/function-calling.js +11 -3
- package/dist/lib/mcp/health-monitor.d.ts +256 -0
- package/dist/lib/mcp/health-monitor.js +621 -0
- package/dist/lib/mcp/logging.js +5 -0
- package/dist/lib/mcp/neurolink-mcp-client.js +2 -1
- package/dist/lib/mcp/orchestrator.d.ts +136 -5
- package/dist/lib/mcp/orchestrator.js +332 -16
- package/dist/lib/mcp/registry.d.ts +71 -16
- package/dist/lib/mcp/registry.js +104 -6
- package/dist/lib/mcp/semaphore-manager.d.ts +137 -0
- package/dist/lib/mcp/semaphore-manager.js +329 -0
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
- package/dist/lib/mcp/servers/ai-providers/ai-workflow-tools.js +5 -4
- package/dist/lib/mcp/session-manager.d.ts +186 -0
- package/dist/lib/mcp/session-manager.js +400 -0
- package/dist/lib/mcp/session-persistence.d.ts +93 -0
- package/dist/lib/mcp/session-persistence.js +298 -0
- package/dist/lib/mcp/tool-integration.js +1 -1
- package/dist/lib/mcp/tool-registry.d.ts +55 -34
- package/dist/lib/mcp/tool-registry.js +111 -97
- package/dist/lib/mcp/transport-manager.d.ts +153 -0
- package/dist/lib/mcp/transport-manager.js +330 -0
- package/dist/lib/mcp/unified-mcp.js +6 -1
- package/dist/lib/mcp/unified-registry.d.ts +54 -5
- package/dist/lib/mcp/unified-registry.js +139 -6
- package/dist/lib/neurolink.d.ts +101 -0
- package/dist/lib/neurolink.js +147 -1
- package/dist/lib/providers/agent-enhanced-provider.d.ts +11 -2
- package/dist/lib/providers/agent-enhanced-provider.js +86 -15
- package/dist/lib/providers/amazonBedrock.d.ts +9 -1
- package/dist/lib/providers/amazonBedrock.js +26 -2
- package/dist/lib/providers/analytics-helper.d.ts +53 -0
- package/dist/lib/providers/analytics-helper.js +151 -0
- package/dist/lib/providers/anthropic.d.ts +11 -1
- package/dist/lib/providers/anthropic.js +29 -4
- package/dist/lib/providers/azureOpenAI.d.ts +3 -1
- package/dist/lib/providers/azureOpenAI.js +28 -4
- package/dist/lib/providers/function-calling-provider.d.ts +9 -1
- package/dist/lib/providers/function-calling-provider.js +14 -1
- package/dist/lib/providers/googleAIStudio.d.ts +15 -1
- package/dist/lib/providers/googleAIStudio.js +32 -2
- package/dist/lib/providers/googleVertexAI.d.ts +9 -1
- package/dist/lib/providers/googleVertexAI.js +31 -2
- package/dist/lib/providers/huggingFace.d.ts +3 -1
- package/dist/lib/providers/huggingFace.js +26 -3
- package/dist/lib/providers/mcp-provider.d.ts +9 -1
- package/dist/lib/providers/mcp-provider.js +12 -0
- package/dist/lib/providers/mistralAI.d.ts +3 -1
- package/dist/lib/providers/mistralAI.js +25 -2
- package/dist/lib/providers/ollama.d.ts +3 -1
- package/dist/lib/providers/ollama.js +27 -4
- package/dist/lib/providers/openAI.d.ts +15 -1
- package/dist/lib/providers/openAI.js +32 -2
- package/dist/lib/proxy/proxy-fetch.js +8 -7
- package/dist/lib/services/streaming/streaming-manager.d.ts +29 -0
- package/dist/lib/services/streaming/streaming-manager.js +244 -0
- package/dist/lib/services/types.d.ts +155 -0
- package/dist/lib/services/types.js +2 -0
- package/dist/lib/services/websocket/websocket-server.d.ts +34 -0
- package/dist/lib/services/websocket/websocket-server.js +304 -0
- package/dist/lib/telemetry/index.d.ts +15 -0
- package/dist/lib/telemetry/index.js +22 -0
- package/dist/lib/telemetry/telemetry-service.d.ts +47 -0
- package/dist/lib/telemetry/telemetry-service.js +259 -0
- package/dist/lib/utils/streaming-utils.d.ts +67 -0
- package/dist/lib/utils/streaming-utils.js +201 -0
- package/dist/mcp/contracts/mcpContract.d.ts +118 -0
- package/dist/mcp/contracts/mcpContract.js +5 -0
- package/dist/mcp/dynamic-chain-executor.d.ts +201 -0
- package/dist/mcp/dynamic-chain-executor.js +489 -0
- package/dist/mcp/dynamic-orchestrator.d.ts +109 -0
- package/dist/mcp/dynamic-orchestrator.js +351 -0
- package/dist/mcp/error-manager.d.ts +254 -0
- package/dist/mcp/error-manager.js +501 -0
- package/dist/mcp/error-recovery.d.ts +158 -0
- package/dist/mcp/error-recovery.js +405 -0
- package/dist/mcp/function-calling.js +11 -3
- package/dist/mcp/health-monitor.d.ts +256 -0
- package/dist/mcp/health-monitor.js +621 -0
- package/dist/mcp/logging.js +5 -0
- package/dist/mcp/neurolink-mcp-client.js +2 -1
- package/dist/mcp/orchestrator.d.ts +136 -5
- package/dist/mcp/orchestrator.js +332 -16
- package/dist/mcp/plugins/core/neurolink-mcp.json +15 -15
- package/dist/mcp/registry.d.ts +71 -16
- package/dist/mcp/registry.js +104 -6
- package/dist/mcp/semaphore-manager.d.ts +137 -0
- package/dist/mcp/semaphore-manager.js +329 -0
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.d.ts +2 -2
- package/dist/mcp/servers/ai-providers/ai-workflow-tools.js +5 -4
- package/dist/mcp/session-manager.d.ts +186 -0
- package/dist/mcp/session-manager.js +400 -0
- package/dist/mcp/session-persistence.d.ts +93 -0
- package/dist/mcp/session-persistence.js +299 -0
- package/dist/mcp/tool-integration.js +1 -1
- package/dist/mcp/tool-registry.d.ts +55 -34
- package/dist/mcp/tool-registry.js +111 -97
- package/dist/mcp/transport-manager.d.ts +153 -0
- package/dist/mcp/transport-manager.js +331 -0
- package/dist/mcp/unified-mcp.js +6 -1
- package/dist/mcp/unified-registry.d.ts +54 -5
- package/dist/mcp/unified-registry.js +139 -6
- package/dist/neurolink.d.ts +101 -0
- package/dist/neurolink.js +147 -1
- package/dist/providers/agent-enhanced-provider.d.ts +11 -2
- package/dist/providers/agent-enhanced-provider.js +86 -15
- package/dist/providers/amazonBedrock.d.ts +9 -1
- package/dist/providers/amazonBedrock.js +26 -2
- package/dist/providers/analytics-helper.d.ts +53 -0
- package/dist/providers/analytics-helper.js +151 -0
- package/dist/providers/anthropic.d.ts +11 -1
- package/dist/providers/anthropic.js +29 -4
- package/dist/providers/azureOpenAI.d.ts +3 -1
- package/dist/providers/azureOpenAI.js +29 -4
- package/dist/providers/function-calling-provider.d.ts +9 -1
- package/dist/providers/function-calling-provider.js +14 -1
- package/dist/providers/googleAIStudio.d.ts +15 -1
- package/dist/providers/googleAIStudio.js +32 -2
- package/dist/providers/googleVertexAI.d.ts +9 -1
- package/dist/providers/googleVertexAI.js +31 -2
- package/dist/providers/huggingFace.d.ts +3 -1
- package/dist/providers/huggingFace.js +26 -3
- package/dist/providers/mcp-provider.d.ts +9 -1
- package/dist/providers/mcp-provider.js +12 -0
- package/dist/providers/mistralAI.d.ts +3 -1
- package/dist/providers/mistralAI.js +25 -2
- package/dist/providers/ollama.d.ts +3 -1
- package/dist/providers/ollama.js +27 -4
- package/dist/providers/openAI.d.ts +15 -1
- package/dist/providers/openAI.js +33 -2
- package/dist/proxy/proxy-fetch.js +8 -7
- package/dist/services/streaming/streaming-manager.d.ts +29 -0
- package/dist/services/streaming/streaming-manager.js +244 -0
- package/dist/services/types.d.ts +155 -0
- package/dist/services/types.js +2 -0
- package/dist/services/websocket/websocket-server.d.ts +34 -0
- package/dist/services/websocket/websocket-server.js +304 -0
- package/dist/telemetry/index.d.ts +15 -0
- package/dist/telemetry/index.js +22 -0
- package/dist/telemetry/telemetry-service.d.ts +47 -0
- package/dist/telemetry/telemetry-service.js +261 -0
- package/dist/utils/streaming-utils.d.ts +67 -0
- package/dist/utils/streaming-utils.js +201 -0
- package/package.json +245 -228
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NeuroLink Session Persistence Layer
|
|
3
|
+
* Provides file-based persistence for sessions with atomic writes and recovery
|
|
4
|
+
*/
|
|
5
|
+
import fs from "fs/promises";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import crypto from "crypto";
|
|
8
|
+
/**
|
|
9
|
+
* Session Persistence Manager
|
|
10
|
+
* Handles saving and loading sessions to/from disk with recovery mechanisms
|
|
11
|
+
*/
|
|
12
|
+
export class SessionPersistence {
|
|
13
|
+
directory;
|
|
14
|
+
snapshotInterval;
|
|
15
|
+
retentionPeriod;
|
|
16
|
+
enableChecksum;
|
|
17
|
+
maxRetries;
|
|
18
|
+
snapshotTimer = null;
|
|
19
|
+
sessionMap;
|
|
20
|
+
constructor(sessionMap, options = {}) {
|
|
21
|
+
this.sessionMap = sessionMap;
|
|
22
|
+
this.directory = options.directory || ".neurolink/sessions";
|
|
23
|
+
this.snapshotInterval = options.snapshotInterval || 30000; // 30 seconds
|
|
24
|
+
this.retentionPeriod = options.retentionPeriod || 86400000; // 24 hours
|
|
25
|
+
this.enableChecksum = options.enableChecksum ?? true;
|
|
26
|
+
this.maxRetries = options.maxRetries || 3;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Initialize persistence layer
|
|
30
|
+
*/
|
|
31
|
+
async initialize() {
|
|
32
|
+
// Create sessions directory if it doesn't exist
|
|
33
|
+
await this.ensureDirectory();
|
|
34
|
+
// Load existing sessions
|
|
35
|
+
await this.loadSessions();
|
|
36
|
+
// Start snapshot timer
|
|
37
|
+
this.startSnapshotTimer();
|
|
38
|
+
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
39
|
+
console.log(`[SessionPersistence] Initialized with directory: ${this.directory}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Ensure sessions directory exists
|
|
44
|
+
*/
|
|
45
|
+
async ensureDirectory() {
|
|
46
|
+
await fs.mkdir(this.directory, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Calculate checksum for data integrity
|
|
50
|
+
*/
|
|
51
|
+
calculateChecksum(data) {
|
|
52
|
+
return crypto.createHash("sha256").update(data).digest("hex");
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Serialize session to JSON with metadata
|
|
56
|
+
*/
|
|
57
|
+
serializeSession(session) {
|
|
58
|
+
// Convert Map to array for JSON serialization
|
|
59
|
+
const sessionData = {
|
|
60
|
+
...session,
|
|
61
|
+
state: Array.from(session.state.entries()),
|
|
62
|
+
};
|
|
63
|
+
let fileData = {
|
|
64
|
+
session: sessionData,
|
|
65
|
+
checksum: "",
|
|
66
|
+
version: "1.0",
|
|
67
|
+
lastSaved: Date.now(),
|
|
68
|
+
};
|
|
69
|
+
if (this.enableChecksum) {
|
|
70
|
+
// First serialization without checksum
|
|
71
|
+
const tempJsonData = JSON.stringify(fileData, null, 2);
|
|
72
|
+
// Calculate checksum based on the first serialization
|
|
73
|
+
fileData.checksum = this.calculateChecksum(tempJsonData);
|
|
74
|
+
}
|
|
75
|
+
// Final serialization with checksum included
|
|
76
|
+
return JSON.stringify(fileData, null, 2);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Deserialize session from JSON
|
|
80
|
+
*/
|
|
81
|
+
deserializeSession(data) {
|
|
82
|
+
try {
|
|
83
|
+
const fileData = JSON.parse(data);
|
|
84
|
+
// Verify checksum if enabled
|
|
85
|
+
if (this.enableChecksum && fileData.checksum) {
|
|
86
|
+
const tempData = { ...fileData, checksum: "" };
|
|
87
|
+
const expectedChecksum = this.calculateChecksum(JSON.stringify(tempData, null, 2));
|
|
88
|
+
if (fileData.checksum !== expectedChecksum) {
|
|
89
|
+
console.error("[SessionPersistence] Checksum mismatch, session corrupted");
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Convert state array back to Map
|
|
94
|
+
const session = fileData.session;
|
|
95
|
+
session.state = new Map(session.state);
|
|
96
|
+
return session;
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
console.error("[SessionPersistence] Failed to deserialize session:", error);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Save single session with atomic write
|
|
105
|
+
*/
|
|
106
|
+
async saveSession(sessionId, session) {
|
|
107
|
+
const filename = `${sessionId}.json`;
|
|
108
|
+
const filepath = path.join(this.directory, filename);
|
|
109
|
+
const tempPath = `${filepath}.tmp`;
|
|
110
|
+
let retries = 0;
|
|
111
|
+
while (retries < this.maxRetries) {
|
|
112
|
+
try {
|
|
113
|
+
// Serialize session
|
|
114
|
+
const data = this.serializeSession(session);
|
|
115
|
+
// Write to temporary file first (atomic write pattern)
|
|
116
|
+
await fs.writeFile(tempPath, data, "utf8");
|
|
117
|
+
// Rename temp file to final location (atomic operation)
|
|
118
|
+
await fs.rename(tempPath, filepath);
|
|
119
|
+
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
120
|
+
console.log(`[SessionPersistence] Saved session ${sessionId}`);
|
|
121
|
+
}
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
retries++;
|
|
126
|
+
console.error(`[SessionPersistence] Failed to save session (attempt ${retries}):`, error);
|
|
127
|
+
// Clean up temp file if it exists
|
|
128
|
+
try {
|
|
129
|
+
await fs.unlink(tempPath);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// Ignore errors when cleaning up temp file
|
|
133
|
+
}
|
|
134
|
+
if (retries < this.maxRetries) {
|
|
135
|
+
// Exponential backoff
|
|
136
|
+
await new Promise((resolve) => setTimeout(resolve, Math.pow(2, retries) * 100));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Load single session from disk
|
|
144
|
+
*/
|
|
145
|
+
async loadSession(sessionId) {
|
|
146
|
+
const filename = `${sessionId}.json`;
|
|
147
|
+
const filepath = path.join(this.directory, filename);
|
|
148
|
+
try {
|
|
149
|
+
const data = await fs.readFile(filepath, "utf8");
|
|
150
|
+
return this.deserializeSession(data);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (error.code !== "ENOENT") {
|
|
154
|
+
console.error(`[SessionPersistence] Failed to load session ${sessionId}:`, error);
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Load all sessions from disk on startup
|
|
161
|
+
*/
|
|
162
|
+
async loadSessions() {
|
|
163
|
+
try {
|
|
164
|
+
const files = await fs.readdir(this.directory);
|
|
165
|
+
const sessionFiles = files.filter((f) => f.endsWith(".json"));
|
|
166
|
+
let loaded = 0;
|
|
167
|
+
let expired = 0;
|
|
168
|
+
for (const file of sessionFiles) {
|
|
169
|
+
const sessionId = file.replace(".json", "");
|
|
170
|
+
const session = await this.loadSession(sessionId);
|
|
171
|
+
if (session) {
|
|
172
|
+
// Check if session is expired
|
|
173
|
+
if (session.expiresAt < Date.now()) {
|
|
174
|
+
expired++;
|
|
175
|
+
// Clean up expired session file
|
|
176
|
+
await this.deleteSession(sessionId);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// Restore to memory
|
|
180
|
+
this.sessionMap.set(sessionId, session);
|
|
181
|
+
loaded++;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
console.log(`[SessionPersistence] Loaded ${loaded} sessions, cleaned ${expired} expired sessions`);
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
console.error("[SessionPersistence] Failed to load sessions:", error);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Save all active sessions (snapshot)
|
|
193
|
+
*/
|
|
194
|
+
async saveAllSessions() {
|
|
195
|
+
const sessions = Array.from(this.sessionMap.entries());
|
|
196
|
+
// Filter out expired sessions and create save promises
|
|
197
|
+
const savePromises = sessions
|
|
198
|
+
.filter(([_, session]) => session.expiresAt >= Date.now())
|
|
199
|
+
.map(async ([sessionId, session]) => {
|
|
200
|
+
return (await this.saveSession(sessionId, session)) ? 1 : 0;
|
|
201
|
+
});
|
|
202
|
+
// Execute all save operations concurrently
|
|
203
|
+
const results = await Promise.all(savePromises);
|
|
204
|
+
const saved = results.reduce((sum, result) => sum + result, 0);
|
|
205
|
+
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
206
|
+
console.log(`[SessionPersistence] Snapshot: saved ${saved}/${sessions.length} sessions`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Delete session file
|
|
211
|
+
*/
|
|
212
|
+
async deleteSession(sessionId) {
|
|
213
|
+
const filename = `${sessionId}.json`;
|
|
214
|
+
const filepath = path.join(this.directory, filename);
|
|
215
|
+
try {
|
|
216
|
+
await fs.unlink(filepath);
|
|
217
|
+
// Keep memory and disk state in sync
|
|
218
|
+
this.sessionMap.delete(sessionId);
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
if (error.code !== "ENOENT") {
|
|
222
|
+
console.error(`[SessionPersistence] Failed to delete session ${sessionId}:`, error);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Clean up old session files
|
|
228
|
+
*/
|
|
229
|
+
async cleanupOldSessions() {
|
|
230
|
+
try {
|
|
231
|
+
const files = await fs.readdir(this.directory);
|
|
232
|
+
const now = Date.now();
|
|
233
|
+
let cleaned = 0;
|
|
234
|
+
for (const file of files) {
|
|
235
|
+
if (!file.endsWith(".json")) {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
const filepath = path.join(this.directory, file);
|
|
239
|
+
const stats = await fs.stat(filepath);
|
|
240
|
+
// Remove files older than retention period
|
|
241
|
+
if (now - stats.mtimeMs > this.retentionPeriod) {
|
|
242
|
+
await fs.unlink(filepath);
|
|
243
|
+
cleaned++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (cleaned > 0) {
|
|
247
|
+
console.log(`[SessionPersistence] Cleaned up ${cleaned} old session files`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
console.error("[SessionPersistence] Cleanup failed:", error);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Start periodic snapshot timer
|
|
256
|
+
*/
|
|
257
|
+
startSnapshotTimer() {
|
|
258
|
+
if (this.snapshotTimer) {
|
|
259
|
+
clearInterval(this.snapshotTimer);
|
|
260
|
+
}
|
|
261
|
+
this.snapshotTimer = setInterval(async () => {
|
|
262
|
+
await this.saveAllSessions();
|
|
263
|
+
await this.cleanupOldSessions();
|
|
264
|
+
}, this.snapshotInterval);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Stop snapshot timer
|
|
268
|
+
*/
|
|
269
|
+
stopSnapshotTimer() {
|
|
270
|
+
if (this.snapshotTimer) {
|
|
271
|
+
clearInterval(this.snapshotTimer);
|
|
272
|
+
this.snapshotTimer = null;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Shutdown persistence layer
|
|
277
|
+
*/
|
|
278
|
+
async shutdown() {
|
|
279
|
+
this.stopSnapshotTimer();
|
|
280
|
+
// Final snapshot before shutdown
|
|
281
|
+
await this.saveAllSessions();
|
|
282
|
+
console.log("[SessionPersistence] Shutdown complete");
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Default session persistence instance
|
|
287
|
+
*/
|
|
288
|
+
export let defaultSessionPersistence = null;
|
|
289
|
+
/**
|
|
290
|
+
* Initialize default session persistence
|
|
291
|
+
*/
|
|
292
|
+
export async function initializeSessionPersistence(sessionMap, options) {
|
|
293
|
+
if (!defaultSessionPersistence) {
|
|
294
|
+
defaultSessionPersistence = new SessionPersistence(sessionMap, options);
|
|
295
|
+
await defaultSessionPersistence.initialize();
|
|
296
|
+
}
|
|
297
|
+
return defaultSessionPersistence;
|
|
298
|
+
}
|
|
@@ -1,40 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Tool Registry - Extended Registry with Tool Management
|
|
3
|
+
* Updated to match industry standard camelCase interfaces
|
|
3
4
|
*/
|
|
4
|
-
import type { ExecutionContext } from "./contracts/
|
|
5
|
+
import type { ExecutionContext, ToolInfo } from "./contracts/mcpContract.js";
|
|
5
6
|
import type { ToolResult } from "./factory.js";
|
|
6
7
|
import { MCPRegistry } from "./registry.js";
|
|
7
|
-
export interface ToolInfo {
|
|
8
|
-
id: string;
|
|
9
|
-
name: string;
|
|
10
|
-
description?: string;
|
|
11
|
-
inputSchema?: any;
|
|
12
|
-
outputSchema?: any;
|
|
13
|
-
serverId: string;
|
|
14
|
-
source: "manual" | "auto" | "default";
|
|
15
|
-
isImplemented?: boolean;
|
|
16
|
-
server?: string;
|
|
17
|
-
}
|
|
18
8
|
export type ToolExecutionResult = ToolResult;
|
|
9
|
+
/**
|
|
10
|
+
* Tool execution options
|
|
11
|
+
*/
|
|
12
|
+
export interface ToolExecutionOptions {
|
|
13
|
+
timeout?: number;
|
|
14
|
+
retries?: number;
|
|
15
|
+
context?: ExecutionContext;
|
|
16
|
+
preferredSource?: string;
|
|
17
|
+
fallbackEnabled?: boolean;
|
|
18
|
+
validateBeforeExecution?: boolean;
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
}
|
|
19
21
|
export declare class MCPToolRegistry extends MCPRegistry {
|
|
20
22
|
private tools;
|
|
21
23
|
private toolExecutionStats;
|
|
22
24
|
/**
|
|
23
|
-
* Register a server with its tools
|
|
24
|
-
*/
|
|
25
|
-
registerServer(serverId: string, serverInfo: any): Promise<void>;
|
|
26
|
-
/**
|
|
27
|
-
* Unregister a server and its tools
|
|
25
|
+
* Register a server with its tools (updated signature)
|
|
28
26
|
*/
|
|
29
|
-
|
|
27
|
+
registerServer(serverId: string, serverConfig?: unknown, context?: ExecutionContext): Promise<void>;
|
|
30
28
|
/**
|
|
31
|
-
* Execute a tool
|
|
29
|
+
* Execute a tool with enhanced context
|
|
32
30
|
*/
|
|
33
|
-
executeTool(toolName: string, args
|
|
31
|
+
executeTool<T = unknown>(toolName: string, args?: unknown, context?: ExecutionContext): Promise<T>;
|
|
34
32
|
/**
|
|
35
|
-
* List all available tools
|
|
33
|
+
* List all available tools (updated signature)
|
|
36
34
|
*/
|
|
37
|
-
listTools(): Promise<ToolInfo[]>;
|
|
35
|
+
listTools(context?: ExecutionContext): Promise<ToolInfo[]>;
|
|
38
36
|
/**
|
|
39
37
|
* Get tool information
|
|
40
38
|
*/
|
|
@@ -44,23 +42,46 @@ export declare class MCPToolRegistry extends MCPRegistry {
|
|
|
44
42
|
*/
|
|
45
43
|
private updateStats;
|
|
46
44
|
/**
|
|
47
|
-
* Get
|
|
45
|
+
* Get execution statistics
|
|
48
46
|
*/
|
|
49
|
-
|
|
47
|
+
getExecutionStats(): Record<string, {
|
|
48
|
+
count: number;
|
|
49
|
+
averageTime: number;
|
|
50
|
+
totalTime: number;
|
|
51
|
+
}>;
|
|
50
52
|
/**
|
|
51
|
-
*
|
|
53
|
+
* Clear execution statistics
|
|
52
54
|
*/
|
|
53
|
-
|
|
55
|
+
clearStats(): void;
|
|
54
56
|
/**
|
|
55
|
-
*
|
|
57
|
+
* Get tools by category
|
|
56
58
|
*/
|
|
57
|
-
|
|
59
|
+
getToolsByCategory(category: string): ToolInfo[];
|
|
60
|
+
/**
|
|
61
|
+
* Check if tool exists
|
|
62
|
+
*/
|
|
63
|
+
hasTool(toolName: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Remove a tool
|
|
66
|
+
*/
|
|
67
|
+
removeTool(toolName: string): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Get tool count
|
|
70
|
+
*/
|
|
71
|
+
getToolCount(): number;
|
|
72
|
+
/**
|
|
73
|
+
* Get statistics (alias for getExecutionStats)
|
|
74
|
+
*/
|
|
75
|
+
getStats(): Record<string, {
|
|
76
|
+
count: number;
|
|
77
|
+
averageTime: number;
|
|
78
|
+
totalTime: number;
|
|
79
|
+
}>;
|
|
80
|
+
/**
|
|
81
|
+
* Unregister a server
|
|
82
|
+
*/
|
|
83
|
+
unregisterServer(serverId: string): boolean;
|
|
58
84
|
}
|
|
59
85
|
export declare const toolRegistry: MCPToolRegistry;
|
|
60
86
|
export declare const defaultToolRegistry: MCPToolRegistry;
|
|
61
|
-
export
|
|
62
|
-
preferredSource?: string;
|
|
63
|
-
fallbackEnabled?: boolean;
|
|
64
|
-
validateBeforeExecution?: boolean;
|
|
65
|
-
timeoutMs?: number;
|
|
66
|
-
}
|
|
87
|
+
export type { ToolInfo } from "./contracts/mcpContract.js";
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP Tool Registry - Extended Registry with Tool Management
|
|
3
|
+
* Updated to match industry standard camelCase interfaces
|
|
3
4
|
*/
|
|
4
5
|
import { MCPRegistry } from "./registry.js";
|
|
5
6
|
import { registryLogger } from "./logging.js";
|
|
@@ -7,91 +8,74 @@ export class MCPToolRegistry extends MCPRegistry {
|
|
|
7
8
|
tools = new Map();
|
|
8
9
|
toolExecutionStats = new Map();
|
|
9
10
|
/**
|
|
10
|
-
* Register a server with its tools
|
|
11
|
+
* Register a server with its tools (updated signature)
|
|
11
12
|
*/
|
|
12
|
-
async registerServer(serverId,
|
|
13
|
+
async registerServer(serverId, serverConfig, context) {
|
|
13
14
|
registryLogger.info(`Registering server: ${serverId}`);
|
|
15
|
+
// Convert to DiscoveredMcp format for compatibility
|
|
16
|
+
const plugin = {
|
|
17
|
+
metadata: {
|
|
18
|
+
name: serverId,
|
|
19
|
+
description: typeof serverConfig === "object" && serverConfig
|
|
20
|
+
? serverConfig.description || "No description"
|
|
21
|
+
: "No description",
|
|
22
|
+
},
|
|
23
|
+
tools: typeof serverConfig === "object" && serverConfig
|
|
24
|
+
? serverConfig.tools
|
|
25
|
+
: {},
|
|
26
|
+
configuration: typeof serverConfig === "object" && serverConfig
|
|
27
|
+
? serverConfig
|
|
28
|
+
: {},
|
|
29
|
+
};
|
|
30
|
+
// Call the parent register method
|
|
31
|
+
this.register(plugin);
|
|
14
32
|
// Extract tools from server info if available
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
source: "manual",
|
|
27
|
-
isImplemented: true,
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Unregister a server and its tools
|
|
34
|
-
*/
|
|
35
|
-
async unregisterServer(serverId) {
|
|
36
|
-
registryLogger.info(`Unregistering server: ${serverId}`);
|
|
37
|
-
// Remove all tools for this server
|
|
38
|
-
for (const [toolId, toolInfo] of this.tools) {
|
|
39
|
-
if (toolInfo.serverId === serverId) {
|
|
40
|
-
this.tools.delete(toolId);
|
|
41
|
-
this.toolExecutionStats.delete(toolId);
|
|
42
|
-
}
|
|
33
|
+
const tools = plugin.tools || {};
|
|
34
|
+
for (const [toolName, toolDef] of Object.entries(tools)) {
|
|
35
|
+
const toolId = `${serverId}.${toolName}`;
|
|
36
|
+
this.tools.set(toolId, {
|
|
37
|
+
name: toolName,
|
|
38
|
+
description: toolDef?.description,
|
|
39
|
+
inputSchema: toolDef?.inputSchema,
|
|
40
|
+
outputSchema: toolDef?.outputSchema,
|
|
41
|
+
serverId,
|
|
42
|
+
category: toolDef?.category || "general",
|
|
43
|
+
});
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
/**
|
|
46
|
-
* Execute a tool
|
|
47
|
+
* Execute a tool with enhanced context
|
|
47
48
|
*/
|
|
48
49
|
async executeTool(toolName, args, context) {
|
|
49
50
|
const startTime = Date.now();
|
|
50
51
|
try {
|
|
51
|
-
const toolInfo = this.getToolInfo(toolName);
|
|
52
|
-
if (!toolInfo) {
|
|
53
|
-
throw new Error(`Tool not found: ${toolName}`);
|
|
54
|
-
}
|
|
55
52
|
registryLogger.info(`Executing tool: ${toolName}`);
|
|
56
|
-
//
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Execute through the plugin (stub implementation)
|
|
62
|
-
const result = {
|
|
63
|
-
success: true,
|
|
64
|
-
data: `Tool ${toolInfo.name} executed with args: ${JSON.stringify(args)}`,
|
|
53
|
+
// Create execution context if not provided
|
|
54
|
+
const execContext = {
|
|
55
|
+
sessionId: context?.sessionId || crypto.randomUUID(),
|
|
56
|
+
userId: context?.userId,
|
|
57
|
+
...context,
|
|
65
58
|
};
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
metadata: {
|
|
72
|
-
toolName,
|
|
73
|
-
executionTime,
|
|
74
|
-
timestamp: Date.now(),
|
|
75
|
-
},
|
|
59
|
+
// Mock execution for now
|
|
60
|
+
const result = {
|
|
61
|
+
result: `Mock execution of ${toolName}`,
|
|
62
|
+
args,
|
|
63
|
+
context: execContext,
|
|
76
64
|
};
|
|
65
|
+
// Update statistics
|
|
66
|
+
const duration = Date.now() - startTime;
|
|
67
|
+
this.updateStats(toolName, duration);
|
|
68
|
+
return result;
|
|
77
69
|
}
|
|
78
70
|
catch (error) {
|
|
79
71
|
registryLogger.error(`Tool execution failed: ${toolName}`, error);
|
|
80
|
-
|
|
81
|
-
success: false,
|
|
82
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
83
|
-
metadata: {
|
|
84
|
-
toolName,
|
|
85
|
-
executionTime: Date.now() - startTime,
|
|
86
|
-
timestamp: Date.now(),
|
|
87
|
-
},
|
|
88
|
-
};
|
|
72
|
+
throw error;
|
|
89
73
|
}
|
|
90
74
|
}
|
|
91
75
|
/**
|
|
92
|
-
* List all available tools
|
|
76
|
+
* List all available tools (updated signature)
|
|
93
77
|
*/
|
|
94
|
-
async listTools() {
|
|
78
|
+
async listTools(context) {
|
|
95
79
|
return Array.from(this.tools.values());
|
|
96
80
|
}
|
|
97
81
|
/**
|
|
@@ -108,53 +92,83 @@ export class MCPToolRegistry extends MCPRegistry {
|
|
|
108
92
|
count: 0,
|
|
109
93
|
totalTime: 0,
|
|
110
94
|
};
|
|
111
|
-
stats.count
|
|
95
|
+
stats.count += 1;
|
|
112
96
|
stats.totalTime += executionTime;
|
|
113
97
|
this.toolExecutionStats.set(toolName, stats);
|
|
114
98
|
}
|
|
115
99
|
/**
|
|
116
|
-
* Get
|
|
100
|
+
* Get execution statistics
|
|
117
101
|
*/
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
averageTime: stats.totalTime / stats.count,
|
|
125
|
-
}
|
|
126
|
-
: null;
|
|
127
|
-
}
|
|
128
|
-
// Return all stats
|
|
129
|
-
const allStats = {};
|
|
130
|
-
for (const [tool, stats] of this.toolExecutionStats) {
|
|
131
|
-
allStats[tool] = {
|
|
132
|
-
...stats,
|
|
102
|
+
getExecutionStats() {
|
|
103
|
+
const result = {};
|
|
104
|
+
for (const [toolName, stats] of this.toolExecutionStats.entries()) {
|
|
105
|
+
result[toolName] = {
|
|
106
|
+
count: stats.count,
|
|
107
|
+
totalTime: stats.totalTime,
|
|
133
108
|
averageTime: stats.totalTime / stats.count,
|
|
134
109
|
};
|
|
135
110
|
}
|
|
136
|
-
return
|
|
111
|
+
return result;
|
|
137
112
|
}
|
|
138
113
|
/**
|
|
139
|
-
*
|
|
114
|
+
* Clear execution statistics
|
|
140
115
|
*/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
totalTools: tools.length,
|
|
145
|
-
totalExecutions: Array.from(this.toolExecutionStats.values()).reduce((acc, stats) => acc + stats.count, 0),
|
|
146
|
-
};
|
|
116
|
+
clearStats() {
|
|
117
|
+
this.toolExecutionStats.clear();
|
|
147
118
|
}
|
|
148
119
|
/**
|
|
149
|
-
*
|
|
120
|
+
* Get tools by category
|
|
150
121
|
*/
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
122
|
+
getToolsByCategory(category) {
|
|
123
|
+
return Array.from(this.tools.values()).filter((tool) => tool.category === category);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if tool exists
|
|
127
|
+
*/
|
|
128
|
+
hasTool(toolName) {
|
|
129
|
+
return this.tools.has(toolName);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Remove a tool
|
|
133
|
+
*/
|
|
134
|
+
removeTool(toolName) {
|
|
135
|
+
const removed = this.tools.delete(toolName);
|
|
136
|
+
if (removed) {
|
|
137
|
+
this.toolExecutionStats.delete(toolName);
|
|
138
|
+
registryLogger.info(`Removed tool: ${toolName}`);
|
|
139
|
+
}
|
|
140
|
+
return removed;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get tool count
|
|
144
|
+
*/
|
|
145
|
+
getToolCount() {
|
|
146
|
+
return this.tools.size;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get statistics (alias for getExecutionStats)
|
|
150
|
+
*/
|
|
151
|
+
getStats() {
|
|
152
|
+
return this.getExecutionStats();
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Unregister a server
|
|
156
|
+
*/
|
|
157
|
+
unregisterServer(serverId) {
|
|
158
|
+
// Remove all tools for this server
|
|
159
|
+
const removedTools = [];
|
|
160
|
+
for (const [toolId, tool] of this.tools.entries()) {
|
|
161
|
+
if (tool.serverId === serverId) {
|
|
162
|
+
this.tools.delete(toolId);
|
|
163
|
+
removedTools.push(toolId);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// Remove from parent registry
|
|
167
|
+
const removed = this.unregister(serverId);
|
|
168
|
+
registryLogger.info(`Unregistered server ${serverId}, removed ${removedTools.length} tools`);
|
|
169
|
+
return removed;
|
|
155
170
|
}
|
|
156
171
|
}
|
|
157
|
-
//
|
|
172
|
+
// Create default instance
|
|
158
173
|
export const toolRegistry = new MCPToolRegistry();
|
|
159
|
-
// Additional exports for backward compatibility
|
|
160
174
|
export const defaultToolRegistry = toolRegistry;
|