@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
|
+
* Phase 3: SSE Chat Utilities
|
|
3
|
+
* Client-side utilities for SSE chat integration
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Client for SSE chat communication
|
|
7
|
+
*/
|
|
8
|
+
export class ChatClient {
|
|
9
|
+
eventSource;
|
|
10
|
+
options;
|
|
11
|
+
messages = [];
|
|
12
|
+
reconnectCount = 0;
|
|
13
|
+
isConnected = false;
|
|
14
|
+
isReconnecting = false;
|
|
15
|
+
reconnectTimeout;
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.options = {
|
|
18
|
+
...options,
|
|
19
|
+
onMessage: options.onMessage || (() => { }),
|
|
20
|
+
onError: options.onError || (() => { }),
|
|
21
|
+
onConnect: options.onConnect || (() => { }),
|
|
22
|
+
onDisconnect: options.onDisconnect || (() => { }),
|
|
23
|
+
reconnectAttempts: options.reconnectAttempts ?? 5,
|
|
24
|
+
reconnectDelay: options.reconnectDelay ?? 1000,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Connect to SSE endpoint
|
|
29
|
+
*/
|
|
30
|
+
connect() {
|
|
31
|
+
if (this.eventSource) {
|
|
32
|
+
this.disconnect();
|
|
33
|
+
}
|
|
34
|
+
const url = new URL("/chat/stream", this.options.endpoint);
|
|
35
|
+
url.searchParams.set("sessionId", this.options.sessionId);
|
|
36
|
+
this.eventSource = new EventSource(url.toString());
|
|
37
|
+
this.eventSource.onopen = () => {
|
|
38
|
+
this.isConnected = true;
|
|
39
|
+
this.isReconnecting = false;
|
|
40
|
+
this.reconnectCount = 0;
|
|
41
|
+
this.options.onConnect();
|
|
42
|
+
};
|
|
43
|
+
this.eventSource.onmessage = (event) => {
|
|
44
|
+
try {
|
|
45
|
+
const sseEvent = JSON.parse(event.data);
|
|
46
|
+
this.handleSSEEvent(sseEvent);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
console.error("Failed to parse SSE event:", error);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
this.eventSource.onerror = (error) => {
|
|
53
|
+
this.isConnected = false;
|
|
54
|
+
this.options.onDisconnect();
|
|
55
|
+
if (this.reconnectCount < this.options.reconnectAttempts) {
|
|
56
|
+
this.isReconnecting = true;
|
|
57
|
+
this.scheduleReconnect();
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
this.isReconnecting = false;
|
|
61
|
+
this.options.onError(new Error("Max reconnection attempts reached"));
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
// Handle specific event types
|
|
65
|
+
this.eventSource.addEventListener("data", (event) => {
|
|
66
|
+
this.handleDataEvent(JSON.parse(event.data));
|
|
67
|
+
});
|
|
68
|
+
this.eventSource.addEventListener("errMsg", (event) => {
|
|
69
|
+
this.handleErrorEvent(JSON.parse(event.data));
|
|
70
|
+
});
|
|
71
|
+
this.eventSource.addEventListener("complete", (event) => {
|
|
72
|
+
this.handleCompleteEvent(JSON.parse(event.data));
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Send message to chat
|
|
77
|
+
*/
|
|
78
|
+
async sendMessage(content) {
|
|
79
|
+
if (!this.isConnected) {
|
|
80
|
+
throw new Error("Not connected to chat server");
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const response = await fetch(`${this.options.endpoint}/chat/send`, {
|
|
84
|
+
method: "POST",
|
|
85
|
+
headers: {
|
|
86
|
+
"Content-Type": "application/json",
|
|
87
|
+
},
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
sessionId: this.options.sessionId,
|
|
90
|
+
message: content,
|
|
91
|
+
}),
|
|
92
|
+
});
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
this.options.onError(error);
|
|
99
|
+
throw error;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Disconnect from SSE endpoint
|
|
104
|
+
*/
|
|
105
|
+
disconnect() {
|
|
106
|
+
if (this.eventSource) {
|
|
107
|
+
this.eventSource.close();
|
|
108
|
+
this.eventSource = undefined;
|
|
109
|
+
}
|
|
110
|
+
if (this.reconnectTimeout) {
|
|
111
|
+
clearTimeout(this.reconnectTimeout);
|
|
112
|
+
this.reconnectTimeout = undefined;
|
|
113
|
+
}
|
|
114
|
+
this.isConnected = false;
|
|
115
|
+
this.isReconnecting = false;
|
|
116
|
+
this.options.onDisconnect();
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Get message history
|
|
120
|
+
*/
|
|
121
|
+
getMessages() {
|
|
122
|
+
return [...this.messages];
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Clear message history
|
|
126
|
+
*/
|
|
127
|
+
clearMessages() {
|
|
128
|
+
this.messages = [];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check connection status
|
|
132
|
+
*/
|
|
133
|
+
getConnectionStatus() {
|
|
134
|
+
return {
|
|
135
|
+
connected: this.isConnected,
|
|
136
|
+
reconnecting: this.isReconnecting,
|
|
137
|
+
reconnectCount: this.reconnectCount,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
handleSSEEvent(event) {
|
|
141
|
+
switch (event.type) {
|
|
142
|
+
case "data":
|
|
143
|
+
this.handleDataEvent(event.data);
|
|
144
|
+
break;
|
|
145
|
+
case "error":
|
|
146
|
+
this.handleErrorEvent(event.data);
|
|
147
|
+
break;
|
|
148
|
+
case "complete":
|
|
149
|
+
this.handleCompleteEvent(event.data);
|
|
150
|
+
break;
|
|
151
|
+
case "heartbeat":
|
|
152
|
+
// Heartbeat received, connection is alive
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
handleDataEvent(data) {
|
|
157
|
+
if (data.type === "chunk") {
|
|
158
|
+
// Handle streaming response chunk
|
|
159
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
160
|
+
if (lastMessage && lastMessage.role === "assistant") {
|
|
161
|
+
// Append to existing assistant message
|
|
162
|
+
lastMessage.content += data.content;
|
|
163
|
+
this.options.onMessage(lastMessage);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// Create new assistant message
|
|
167
|
+
const message = {
|
|
168
|
+
id: `msg_${Date.now()}_assistant`,
|
|
169
|
+
role: "assistant",
|
|
170
|
+
content: data.content,
|
|
171
|
+
timestamp: Date.now(),
|
|
172
|
+
};
|
|
173
|
+
this.messages.push(message);
|
|
174
|
+
this.options.onMessage(message);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (data.type === "start") {
|
|
178
|
+
// New conversation started
|
|
179
|
+
const userMessage = {
|
|
180
|
+
id: data.messageId,
|
|
181
|
+
role: "user",
|
|
182
|
+
content: data.content || "", // Use data content if available
|
|
183
|
+
timestamp: Date.now(),
|
|
184
|
+
};
|
|
185
|
+
this.messages.push(userMessage);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
handleErrorEvent(data) {
|
|
189
|
+
this.options.onError(new Error(data.message || "Chat error"));
|
|
190
|
+
}
|
|
191
|
+
handleCompleteEvent(data) {
|
|
192
|
+
// Message completion - final processing
|
|
193
|
+
if (data.totalTokens) {
|
|
194
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
195
|
+
if (lastMessage) {
|
|
196
|
+
// Initialize metadata if it doesn't exist
|
|
197
|
+
if (!lastMessage.metadata) {
|
|
198
|
+
lastMessage.metadata = {};
|
|
199
|
+
}
|
|
200
|
+
lastMessage.metadata.tokens = data.totalTokens;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
scheduleReconnect() {
|
|
205
|
+
const delay = this.options.reconnectDelay * Math.pow(2, this.reconnectCount);
|
|
206
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
207
|
+
this.reconnectCount++;
|
|
208
|
+
this.reconnectTimeout = undefined;
|
|
209
|
+
this.connect();
|
|
210
|
+
}, delay);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Create chat client instance
|
|
215
|
+
*/
|
|
216
|
+
export function createChatClient(options) {
|
|
217
|
+
return new ChatClient(options);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* React-style hook for chat streaming (can be adapted for other frameworks)
|
|
221
|
+
*/
|
|
222
|
+
export function useChatStream(options) {
|
|
223
|
+
// This would typically use React hooks or similar framework state management
|
|
224
|
+
// For now, providing a basic implementation that can be extended
|
|
225
|
+
const client = new ChatClient(options);
|
|
226
|
+
// Connect on creation
|
|
227
|
+
client.connect();
|
|
228
|
+
return {
|
|
229
|
+
get messages() {
|
|
230
|
+
return client.getMessages();
|
|
231
|
+
},
|
|
232
|
+
get isConnected() {
|
|
233
|
+
return client.getConnectionStatus().connected;
|
|
234
|
+
},
|
|
235
|
+
get isReconnecting() {
|
|
236
|
+
return client.getConnectionStatus().reconnecting;
|
|
237
|
+
},
|
|
238
|
+
sendMessage: async (content) => {
|
|
239
|
+
await client.sendMessage(content);
|
|
240
|
+
},
|
|
241
|
+
disconnect: () => {
|
|
242
|
+
client.disconnect();
|
|
243
|
+
},
|
|
244
|
+
reconnect: () => {
|
|
245
|
+
client.connect();
|
|
246
|
+
},
|
|
247
|
+
clearHistory: () => {
|
|
248
|
+
client.clearMessages();
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Utility for creating SSE EventSource with automatic reconnection
|
|
254
|
+
*/
|
|
255
|
+
export function createSSEConnection(url, options = {}) {
|
|
256
|
+
let eventSource = null;
|
|
257
|
+
let reconnectCount = 0;
|
|
258
|
+
let isConnected = false;
|
|
259
|
+
const maxAttempts = options.maxReconnectAttempts ?? 5;
|
|
260
|
+
const connect = () => {
|
|
261
|
+
if (eventSource) {
|
|
262
|
+
eventSource.close();
|
|
263
|
+
}
|
|
264
|
+
eventSource = new EventSource(url);
|
|
265
|
+
eventSource.onopen = () => {
|
|
266
|
+
isConnected = true;
|
|
267
|
+
reconnectCount = 0;
|
|
268
|
+
options.onOpen?.();
|
|
269
|
+
};
|
|
270
|
+
eventSource.onmessage = (event) => {
|
|
271
|
+
options.onMessage?.(event);
|
|
272
|
+
};
|
|
273
|
+
eventSource.onerror = () => {
|
|
274
|
+
isConnected = false;
|
|
275
|
+
if (options.reconnect && reconnectCount < maxAttempts) {
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
reconnectCount++;
|
|
278
|
+
connect();
|
|
279
|
+
}, 1000 * Math.pow(2, reconnectCount));
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
options.onError?.(new Error("SSE connection failed"));
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
};
|
|
286
|
+
const disconnect = () => {
|
|
287
|
+
if (eventSource) {
|
|
288
|
+
eventSource.close();
|
|
289
|
+
eventSource = null;
|
|
290
|
+
}
|
|
291
|
+
isConnected = false;
|
|
292
|
+
};
|
|
293
|
+
return {
|
|
294
|
+
connect,
|
|
295
|
+
disconnect,
|
|
296
|
+
isConnected: () => isConnected,
|
|
297
|
+
};
|
|
298
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 3: SSE Chat Utilities
|
|
3
|
+
* Main chat module exports
|
|
4
|
+
*/
|
|
5
|
+
import { SSEChatHandler } from "./sse-handler.js";
|
|
6
|
+
export { SSEChatHandler } from "./sse-handler.js";
|
|
7
|
+
export { ChatSession } from "./session.js";
|
|
8
|
+
export { MemorySessionStorage, FileSessionStorage, RedisSessionStorage, SessionStorageFactory, } from "./session-storage.js";
|
|
9
|
+
export { createChatClient, useChatStream } from "./client-utils.js";
|
|
10
|
+
export type { ChatMessage, ChatRequest, SSEOptions, SessionOptions, SSEEvent, ChatSessionState, StreamingChatResponse, SessionStorage, ContextManager, } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Quick setup helper for SSE chat
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSSEChat(provider: any, options?: any): Promise<SSEChatHandler>;
|
|
15
|
+
/**
|
|
16
|
+
* Quick setup helper for chat session
|
|
17
|
+
*/
|
|
18
|
+
export declare function createChatSession(sessionId: string, options?: any): Promise<import("./session.js").ChatSession>;
|
|
19
|
+
/**
|
|
20
|
+
* Enhanced factory function for real-time chat
|
|
21
|
+
*/
|
|
22
|
+
export declare function createEnhancedChatService(options: {
|
|
23
|
+
provider: any;
|
|
24
|
+
enableSSE?: boolean;
|
|
25
|
+
enableWebSocket?: boolean;
|
|
26
|
+
streamingConfig?: any;
|
|
27
|
+
}): Promise<SSEChatHandler>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 3: SSE Chat Utilities
|
|
3
|
+
* Main chat module exports
|
|
4
|
+
*/
|
|
5
|
+
import { SSEChatHandler } from "./sse-handler.js";
|
|
6
|
+
export { SSEChatHandler } from "./sse-handler.js";
|
|
7
|
+
export { ChatSession } from "./session.js";
|
|
8
|
+
export { MemorySessionStorage, FileSessionStorage, RedisSessionStorage, SessionStorageFactory, } from "./session-storage.js";
|
|
9
|
+
export { createChatClient, useChatStream } from "./client-utils.js";
|
|
10
|
+
/**
|
|
11
|
+
* Quick setup helper for SSE chat
|
|
12
|
+
*/
|
|
13
|
+
export async function createSSEChat(provider, options) {
|
|
14
|
+
const { SSEChatHandler } = await import("./sse-handler.js");
|
|
15
|
+
return new SSEChatHandler(provider, options);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Quick setup helper for chat session
|
|
19
|
+
*/
|
|
20
|
+
export async function createChatSession(sessionId, options) {
|
|
21
|
+
const { ChatSession } = await import("./session.js");
|
|
22
|
+
return new ChatSession(sessionId, options);
|
|
23
|
+
}
|
|
24
|
+
// Real-time Services (Phase 4) - Temporarily disabled for testing
|
|
25
|
+
// export { WebSocketChatHandler } from './websocket-chat-handler.js';
|
|
26
|
+
// export { NeuroLinkWebSocketServer } from '../services/websocket/websocket-server.js';
|
|
27
|
+
// export { StreamingManager } from '../services/streaming/streaming-manager.js';
|
|
28
|
+
// export * from '../services/types.js';
|
|
29
|
+
/**
|
|
30
|
+
* Enhanced factory function for real-time chat
|
|
31
|
+
*/
|
|
32
|
+
export async function createEnhancedChatService(options) {
|
|
33
|
+
if (options.enableWebSocket) {
|
|
34
|
+
const { WebSocketChatHandler } = await import("./websocket-chat-handler.js");
|
|
35
|
+
return new WebSocketChatHandler(options.provider, {
|
|
36
|
+
sseOptions: options.enableSSE ? {} : undefined,
|
|
37
|
+
wsOptions: options.streamingConfig,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return new SSEChatHandler(options.provider);
|
|
41
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 3: SSE Chat Utilities
|
|
3
|
+
* Session storage adapters for persistence
|
|
4
|
+
*/
|
|
5
|
+
import type { SessionStorage, ChatSessionState } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* In-memory session storage (default)
|
|
8
|
+
*/
|
|
9
|
+
export declare class MemorySessionStorage implements SessionStorage {
|
|
10
|
+
private sessions;
|
|
11
|
+
get(sessionId: string): Promise<ChatSessionState | null>;
|
|
12
|
+
set(sessionId: string, state: ChatSessionState): Promise<void>;
|
|
13
|
+
delete(sessionId: string): Promise<void>;
|
|
14
|
+
list(): Promise<string[]>;
|
|
15
|
+
cleanup(maxAge: number): Promise<number>;
|
|
16
|
+
/**
|
|
17
|
+
* Get storage statistics
|
|
18
|
+
*/
|
|
19
|
+
getStats(): {
|
|
20
|
+
totalSessions: number;
|
|
21
|
+
memoryUsageBytes: number;
|
|
22
|
+
oldestSession?: number;
|
|
23
|
+
newestSession?: number;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Clear all sessions
|
|
27
|
+
*/
|
|
28
|
+
clear(): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* File-based session storage
|
|
32
|
+
*/
|
|
33
|
+
export declare class FileSessionStorage implements SessionStorage {
|
|
34
|
+
private basePath;
|
|
35
|
+
private constructor();
|
|
36
|
+
static create(basePath?: string): Promise<FileSessionStorage>;
|
|
37
|
+
get(sessionId: string): Promise<ChatSessionState | null>;
|
|
38
|
+
set(sessionId: string, state: ChatSessionState): Promise<void>;
|
|
39
|
+
delete(sessionId: string): Promise<void>;
|
|
40
|
+
list(): Promise<string[]>;
|
|
41
|
+
cleanup(maxAge: number): Promise<number>;
|
|
42
|
+
private getFilePath;
|
|
43
|
+
private ensureDirectory;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Redis session storage (for production scaling)
|
|
47
|
+
*/
|
|
48
|
+
interface RedisClient {
|
|
49
|
+
get(key: string): Promise<string | null>;
|
|
50
|
+
set(key: string, value: string, options?: any): Promise<any>;
|
|
51
|
+
del(key: string): Promise<number>;
|
|
52
|
+
exists(key: string): Promise<number>;
|
|
53
|
+
expire?(key: string, ttl: number): Promise<any>;
|
|
54
|
+
keys?(pattern: string): Promise<string[]>;
|
|
55
|
+
}
|
|
56
|
+
export declare class RedisSessionStorage implements SessionStorage {
|
|
57
|
+
private client;
|
|
58
|
+
private keyPrefix;
|
|
59
|
+
constructor(redisClient: RedisClient, keyPrefix?: string);
|
|
60
|
+
get(sessionId: string): Promise<ChatSessionState | null>;
|
|
61
|
+
set(sessionId: string, state: ChatSessionState): Promise<void>;
|
|
62
|
+
delete(sessionId: string): Promise<void>;
|
|
63
|
+
list(): Promise<string[]>;
|
|
64
|
+
cleanup(maxAge: number): Promise<number>;
|
|
65
|
+
private getKey;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Session storage factory
|
|
69
|
+
*/
|
|
70
|
+
export declare class SessionStorageFactory {
|
|
71
|
+
static create(type: "memory" | "file" | "redis", options?: {
|
|
72
|
+
basePath?: string;
|
|
73
|
+
redisClient?: RedisClient;
|
|
74
|
+
keyPrefix?: string;
|
|
75
|
+
}): Promise<SessionStorage>;
|
|
76
|
+
}
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 3: SSE Chat Utilities
|
|
3
|
+
* Session storage adapters for persistence
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from "fs";
|
|
6
|
+
/**
|
|
7
|
+
* In-memory session storage (default)
|
|
8
|
+
*/
|
|
9
|
+
export class MemorySessionStorage {
|
|
10
|
+
sessions = new Map();
|
|
11
|
+
async get(sessionId) {
|
|
12
|
+
return this.sessions.get(sessionId) || null;
|
|
13
|
+
}
|
|
14
|
+
async set(sessionId, state) {
|
|
15
|
+
this.sessions.set(sessionId, state);
|
|
16
|
+
}
|
|
17
|
+
async delete(sessionId) {
|
|
18
|
+
this.sessions.delete(sessionId);
|
|
19
|
+
}
|
|
20
|
+
async list() {
|
|
21
|
+
return Array.from(this.sessions.keys());
|
|
22
|
+
}
|
|
23
|
+
async cleanup(maxAge) {
|
|
24
|
+
const now = Date.now();
|
|
25
|
+
let removed = 0;
|
|
26
|
+
for (const [sessionId, state] of this.sessions.entries()) {
|
|
27
|
+
if (now - state.lastActivity > maxAge) {
|
|
28
|
+
this.sessions.delete(sessionId);
|
|
29
|
+
removed++;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return removed;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Get storage statistics
|
|
36
|
+
*/
|
|
37
|
+
getStats() {
|
|
38
|
+
const sessions = Array.from(this.sessions.values());
|
|
39
|
+
const memoryUsageBytes = Buffer.byteLength(JSON.stringify(sessions), "utf8");
|
|
40
|
+
const timestamps = sessions.map((s) => s.lastActivity);
|
|
41
|
+
return {
|
|
42
|
+
totalSessions: this.sessions.size,
|
|
43
|
+
memoryUsageBytes,
|
|
44
|
+
oldestSession: timestamps.length > 0 ? Math.min(...timestamps) : undefined,
|
|
45
|
+
newestSession: timestamps.length > 0 ? Math.max(...timestamps) : undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Clear all sessions
|
|
50
|
+
*/
|
|
51
|
+
async clear() {
|
|
52
|
+
this.sessions.clear();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* File-based session storage
|
|
57
|
+
*/
|
|
58
|
+
export class FileSessionStorage {
|
|
59
|
+
basePath;
|
|
60
|
+
constructor(basePath) {
|
|
61
|
+
this.basePath = basePath;
|
|
62
|
+
}
|
|
63
|
+
static async create(basePath = "./sessions") {
|
|
64
|
+
const instance = new FileSessionStorage(basePath);
|
|
65
|
+
await instance.ensureDirectory();
|
|
66
|
+
return instance;
|
|
67
|
+
}
|
|
68
|
+
async get(sessionId) {
|
|
69
|
+
try {
|
|
70
|
+
const filePath = this.getFilePath(sessionId);
|
|
71
|
+
const data = await fs.readFile(filePath, "utf-8");
|
|
72
|
+
return JSON.parse(data);
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
if (error?.code === "ENOENT") {
|
|
76
|
+
return null; // File doesn't exist
|
|
77
|
+
}
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async set(sessionId, state) {
|
|
82
|
+
const filePath = this.getFilePath(sessionId);
|
|
83
|
+
const data = JSON.stringify({
|
|
84
|
+
...state,
|
|
85
|
+
lastActivity: state.lastActivity ?? Date.now(),
|
|
86
|
+
}, null, 2);
|
|
87
|
+
await fs.writeFile(filePath, data, "utf-8");
|
|
88
|
+
}
|
|
89
|
+
async delete(sessionId) {
|
|
90
|
+
try {
|
|
91
|
+
const filePath = this.getFilePath(sessionId);
|
|
92
|
+
await fs.unlink(filePath);
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
if (error?.code !== "ENOENT") {
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async list() {
|
|
101
|
+
try {
|
|
102
|
+
const files = await fs.readdir(this.basePath);
|
|
103
|
+
return files
|
|
104
|
+
.filter((file) => file.endsWith(".json"))
|
|
105
|
+
.map((file) => file.replace(".json", ""));
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async cleanup(maxAge) {
|
|
112
|
+
const sessionIds = await this.list();
|
|
113
|
+
const now = Date.now();
|
|
114
|
+
let removed = 0;
|
|
115
|
+
for (const sessionId of sessionIds) {
|
|
116
|
+
const state = await this.get(sessionId);
|
|
117
|
+
if (state && now - state.lastActivity > maxAge) {
|
|
118
|
+
await this.delete(sessionId);
|
|
119
|
+
removed++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return removed;
|
|
123
|
+
}
|
|
124
|
+
getFilePath(sessionId) {
|
|
125
|
+
return `${this.basePath}/${sessionId}.json`;
|
|
126
|
+
}
|
|
127
|
+
async ensureDirectory() {
|
|
128
|
+
try {
|
|
129
|
+
await fs.mkdir(this.basePath, { recursive: true });
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (error?.code !== "EEXIST") {
|
|
133
|
+
throw error; // Rethrow unexpected errors
|
|
134
|
+
}
|
|
135
|
+
// Directory already exists, which is fine
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export class RedisSessionStorage {
|
|
140
|
+
client;
|
|
141
|
+
keyPrefix;
|
|
142
|
+
constructor(redisClient, keyPrefix = "neurolink:session:") {
|
|
143
|
+
this.client = redisClient;
|
|
144
|
+
this.keyPrefix = keyPrefix;
|
|
145
|
+
}
|
|
146
|
+
async get(sessionId) {
|
|
147
|
+
try {
|
|
148
|
+
const data = await this.client.get(this.getKey(sessionId));
|
|
149
|
+
return data ? JSON.parse(data) : null;
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
console.error("Redis get error:", error);
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async set(sessionId, state) {
|
|
157
|
+
try {
|
|
158
|
+
const key = this.getKey(sessionId);
|
|
159
|
+
const data = JSON.stringify({
|
|
160
|
+
...state,
|
|
161
|
+
lastActivity: Date.now(),
|
|
162
|
+
});
|
|
163
|
+
await this.client.set(key, data);
|
|
164
|
+
// Set TTL if supported
|
|
165
|
+
if (this.client.expire) {
|
|
166
|
+
await this.client.expire(key, 3600); // 1 hour default
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
console.error("Redis set error:", error);
|
|
171
|
+
throw error;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
async delete(sessionId) {
|
|
175
|
+
try {
|
|
176
|
+
await this.client.del(this.getKey(sessionId));
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
console.error("Redis delete error:", error);
|
|
180
|
+
throw error;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
async list() {
|
|
184
|
+
try {
|
|
185
|
+
if (!this.client.keys) {
|
|
186
|
+
console.warn("Redis client does not support keys operation");
|
|
187
|
+
return [];
|
|
188
|
+
}
|
|
189
|
+
const keys = await this.client.keys(`${this.keyPrefix}*`);
|
|
190
|
+
return keys.map((key) => key.replace(this.keyPrefix, ""));
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
console.error("Redis list error:", error);
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async cleanup(maxAge) {
|
|
198
|
+
const sessionIds = await this.list();
|
|
199
|
+
const now = Date.now();
|
|
200
|
+
let removed = 0;
|
|
201
|
+
for (const sessionId of sessionIds) {
|
|
202
|
+
const state = await this.get(sessionId);
|
|
203
|
+
if (state && now - state.lastActivity > maxAge) {
|
|
204
|
+
await this.delete(sessionId);
|
|
205
|
+
removed++;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return removed;
|
|
209
|
+
}
|
|
210
|
+
getKey(sessionId) {
|
|
211
|
+
return `${this.keyPrefix}${sessionId}`;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Session storage factory
|
|
216
|
+
*/
|
|
217
|
+
export class SessionStorageFactory {
|
|
218
|
+
static async create(type, options) {
|
|
219
|
+
switch (type) {
|
|
220
|
+
case "memory":
|
|
221
|
+
return new MemorySessionStorage();
|
|
222
|
+
case "file":
|
|
223
|
+
return await FileSessionStorage.create(options?.basePath);
|
|
224
|
+
case "redis":
|
|
225
|
+
if (!options?.redisClient) {
|
|
226
|
+
throw new Error("Redis client required for Redis storage");
|
|
227
|
+
}
|
|
228
|
+
return new RedisSessionStorage(options.redisClient, options.keyPrefix);
|
|
229
|
+
default:
|
|
230
|
+
throw new Error(`Unknown storage type: ${type}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|