@juspay/neurolink 7.48.1 → 7.49.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 +13 -0
- package/README.md +215 -16
- package/dist/agent/directTools.d.ts +55 -0
- package/dist/agent/directTools.js +266 -0
- package/dist/cli/factories/commandFactory.d.ts +2 -0
- package/dist/cli/factories/commandFactory.js +130 -16
- package/dist/cli/index.js +0 -0
- package/dist/cli/loop/conversationSelector.d.ts +45 -0
- package/dist/cli/loop/conversationSelector.js +222 -0
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/loop/session.d.ts +36 -8
- package/dist/cli/loop/session.js +257 -61
- package/dist/core/baseProvider.js +9 -2
- package/dist/core/evaluation.js +5 -2
- package/dist/factories/providerRegistry.js +2 -2
- package/dist/lib/agent/directTools.d.ts +55 -0
- package/dist/lib/agent/directTools.js +266 -0
- package/dist/lib/core/baseProvider.js +9 -2
- package/dist/lib/core/evaluation.js +5 -2
- package/dist/lib/factories/providerRegistry.js +2 -2
- package/dist/lib/mcp/factory.d.ts +2 -157
- package/dist/lib/mcp/flexibleToolValidator.d.ts +1 -5
- package/dist/lib/mcp/index.d.ts +3 -2
- package/dist/lib/mcp/mcpCircuitBreaker.d.ts +1 -75
- package/dist/lib/mcp/mcpClientFactory.d.ts +1 -20
- package/dist/lib/mcp/mcpClientFactory.js +1 -0
- package/dist/lib/mcp/registry.d.ts +3 -10
- package/dist/lib/mcp/servers/agent/directToolsServer.d.ts +1 -1
- package/dist/lib/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
- package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
- package/dist/lib/mcp/toolDiscoveryService.d.ts +3 -84
- package/dist/lib/mcp/toolRegistry.d.ts +2 -24
- package/dist/lib/middleware/builtin/guardrails.d.ts +5 -16
- package/dist/lib/middleware/builtin/guardrails.js +44 -39
- package/dist/lib/middleware/utils/guardrailsUtils.d.ts +64 -0
- package/dist/lib/middleware/utils/guardrailsUtils.js +387 -0
- package/dist/lib/neurolink.d.ts +1 -1
- package/dist/lib/providers/anthropic.js +46 -3
- package/dist/lib/providers/azureOpenai.js +8 -2
- package/dist/lib/providers/googleAiStudio.js +8 -2
- package/dist/lib/providers/googleVertex.js +11 -2
- package/dist/lib/providers/huggingFace.js +1 -1
- package/dist/lib/providers/litellm.js +1 -1
- package/dist/lib/providers/mistral.js +1 -1
- package/dist/lib/providers/openAI.js +46 -3
- package/dist/lib/session/globalSessionState.d.ts +26 -0
- package/dist/lib/session/globalSessionState.js +49 -0
- package/dist/lib/types/cli.d.ts +28 -0
- package/dist/lib/types/content.d.ts +18 -5
- package/dist/lib/types/contextTypes.d.ts +1 -1
- package/dist/lib/types/conversation.d.ts +55 -4
- package/dist/lib/types/fileTypes.d.ts +65 -0
- package/dist/lib/types/fileTypes.js +4 -0
- package/dist/lib/types/generateTypes.d.ts +12 -0
- package/dist/lib/types/guardrails.d.ts +103 -0
- package/dist/lib/types/guardrails.js +1 -0
- package/dist/lib/types/index.d.ts +4 -2
- package/dist/lib/types/index.js +4 -0
- package/dist/lib/types/mcpTypes.d.ts +407 -14
- package/dist/lib/types/streamTypes.d.ts +7 -0
- package/dist/lib/types/tools.d.ts +132 -35
- package/dist/lib/utils/csvProcessor.d.ts +68 -0
- package/dist/lib/utils/csvProcessor.js +277 -0
- package/dist/lib/utils/fileDetector.d.ts +57 -0
- package/dist/lib/utils/fileDetector.js +457 -0
- package/dist/lib/utils/imageProcessor.d.ts +10 -0
- package/dist/lib/utils/imageProcessor.js +22 -0
- package/dist/lib/utils/loopUtils.d.ts +71 -0
- package/dist/lib/utils/loopUtils.js +262 -0
- package/dist/lib/utils/messageBuilder.d.ts +2 -1
- package/dist/lib/utils/messageBuilder.js +197 -2
- package/dist/lib/utils/optionsUtils.d.ts +1 -1
- package/dist/mcp/factory.d.ts +2 -157
- package/dist/mcp/flexibleToolValidator.d.ts +1 -5
- package/dist/mcp/index.d.ts +3 -2
- package/dist/mcp/mcpCircuitBreaker.d.ts +1 -75
- package/dist/mcp/mcpClientFactory.d.ts +1 -20
- package/dist/mcp/mcpClientFactory.js +1 -0
- package/dist/mcp/registry.d.ts +3 -10
- package/dist/mcp/servers/agent/directToolsServer.d.ts +1 -1
- package/dist/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
- package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
- package/dist/mcp/toolDiscoveryService.d.ts +3 -84
- package/dist/mcp/toolRegistry.d.ts +2 -24
- package/dist/middleware/builtin/guardrails.d.ts +5 -16
- package/dist/middleware/builtin/guardrails.js +44 -39
- package/dist/middleware/utils/guardrailsUtils.d.ts +64 -0
- package/dist/middleware/utils/guardrailsUtils.js +387 -0
- package/dist/neurolink.d.ts +1 -1
- package/dist/providers/anthropic.js +46 -3
- package/dist/providers/azureOpenai.js +8 -2
- package/dist/providers/googleAiStudio.js +8 -2
- package/dist/providers/googleVertex.js +11 -2
- package/dist/providers/huggingFace.js +1 -1
- package/dist/providers/litellm.js +1 -1
- package/dist/providers/mistral.js +1 -1
- package/dist/providers/openAI.js +46 -3
- package/dist/session/globalSessionState.d.ts +26 -0
- package/dist/session/globalSessionState.js +49 -0
- package/dist/types/cli.d.ts +28 -0
- package/dist/types/content.d.ts +18 -5
- package/dist/types/contextTypes.d.ts +1 -1
- package/dist/types/conversation.d.ts +55 -4
- package/dist/types/fileTypes.d.ts +65 -0
- package/dist/types/fileTypes.js +4 -0
- package/dist/types/generateTypes.d.ts +12 -0
- package/dist/types/guardrails.d.ts +103 -0
- package/dist/types/guardrails.js +1 -0
- package/dist/types/index.d.ts +4 -2
- package/dist/types/index.js +4 -0
- package/dist/types/mcpTypes.d.ts +407 -14
- package/dist/types/modelTypes.d.ts +6 -6
- package/dist/types/streamTypes.d.ts +7 -0
- package/dist/types/tools.d.ts +132 -35
- package/dist/utils/csvProcessor.d.ts +68 -0
- package/dist/utils/csvProcessor.js +277 -0
- package/dist/utils/fileDetector.d.ts +57 -0
- package/dist/utils/fileDetector.js +457 -0
- package/dist/utils/imageProcessor.d.ts +10 -0
- package/dist/utils/imageProcessor.js +22 -0
- package/dist/utils/loopUtils.d.ts +71 -0
- package/dist/utils/loopUtils.js +262 -0
- package/dist/utils/messageBuilder.d.ts +2 -1
- package/dist/utils/messageBuilder.js +197 -2
- package/dist/utils/optionsUtils.d.ts +1 -1
- package/package.json +9 -3
- package/dist/lib/mcp/contracts/mcpContract.d.ts +0 -106
- package/dist/lib/mcp/contracts/mcpContract.js +0 -5
- package/dist/mcp/contracts/mcpContract.d.ts +0 -106
- package/dist/mcp/contracts/mcpContract.js +0 -5
package/dist/cli/loop/session.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import readline from "readline";
|
|
3
|
-
import fs from "fs/promises";
|
|
4
|
-
import path from "path";
|
|
5
|
-
import os from "os";
|
|
6
3
|
import { logger } from "../../lib/utils/logger.js";
|
|
7
4
|
import { globalSession } from "../../lib/session/globalSessionState.js";
|
|
8
5
|
import { textGenerationOptionsSchema } from "./optionsSchema.js";
|
|
9
6
|
import { handleError } from "../errorHandler.js";
|
|
7
|
+
import { ConversationSelector } from "./conversationSelector.js";
|
|
8
|
+
import { NeuroLink } from "../../lib/neurolink.js";
|
|
9
|
+
import { displaySessionMessage, verifyConversationContext, getConversationPreview, loadCommandHistory, saveCommandToHistory, displayConversationPreview, parseValue, restoreSessionVariables, } from "../../lib/utils/loopUtils.js";
|
|
10
10
|
// Banner Art
|
|
11
11
|
const NEUROLINK_BANNER = `
|
|
12
12
|
▗▖ ▗▖▗▄▄▄▖▗▖ ▗▖▗▄▄▖ ▗▄▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▖ ▗▖
|
|
@@ -14,33 +14,58 @@ const NEUROLINK_BANNER = `
|
|
|
14
14
|
▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▌▐▛▀▚▖▐▌ ▐▌▐▌ █ ▐▌ ▝▜▌▐▛▚▖
|
|
15
15
|
▐▌ ▐▌▐▙▄▄▖▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘▐▙▄▄▖▗▄█▄▖▐▌ ▐▌▐▌ ▐▌
|
|
16
16
|
`;
|
|
17
|
-
// Global command history file
|
|
18
|
-
const HISTORY_FILE = path.join(os.homedir(), ".neurolink_history");
|
|
19
17
|
export class LoopSession {
|
|
20
18
|
conversationMemoryConfig;
|
|
19
|
+
options;
|
|
21
20
|
initializeCliParser;
|
|
22
21
|
isRunning = false;
|
|
23
22
|
sessionId;
|
|
24
23
|
commandHistory = [];
|
|
25
24
|
sessionVariablesSchema = textGenerationOptionsSchema;
|
|
26
|
-
constructor(initializeCliParser, conversationMemoryConfig) {
|
|
25
|
+
constructor(initializeCliParser, conversationMemoryConfig, options) {
|
|
27
26
|
this.conversationMemoryConfig = conversationMemoryConfig;
|
|
27
|
+
this.options = options;
|
|
28
28
|
this.initializeCliParser = initializeCliParser;
|
|
29
29
|
}
|
|
30
30
|
async start() {
|
|
31
31
|
// Initialize global session state
|
|
32
32
|
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
33
33
|
// Load command history from global file, reverse once for most recent first
|
|
34
|
-
this.commandHistory = (await
|
|
34
|
+
this.commandHistory = (await loadCommandHistory()).reverse();
|
|
35
35
|
this.isRunning = true;
|
|
36
36
|
logger.always(chalk.bold.green(NEUROLINK_BANNER));
|
|
37
37
|
logger.always(chalk.bold.green("Welcome to NeuroLink Loop Mode!"));
|
|
38
|
+
// Check for direct CLI options
|
|
39
|
+
const directResumeSessionId = this.options?.directResumeSessionId;
|
|
40
|
+
const forceNewSession = this.options?.forceNewSession;
|
|
41
|
+
// Handle conversation discovery and selection if memory is enabled
|
|
38
42
|
if (this.conversationMemoryConfig?.enabled) {
|
|
39
|
-
logger.always(chalk.gray(`Session ID: ${this.sessionId}`));
|
|
40
43
|
logger.always(chalk.gray("Conversation memory enabled"));
|
|
44
|
+
// Handle direct resume option
|
|
45
|
+
if (directResumeSessionId) {
|
|
46
|
+
await this.handleDirectSessionResume(directResumeSessionId);
|
|
47
|
+
}
|
|
48
|
+
// Handle force new session option
|
|
49
|
+
else if (forceNewSession) {
|
|
50
|
+
logger.always(chalk.blue("Force starting new conversation..."));
|
|
51
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
52
|
+
}
|
|
53
|
+
// Default behavior: check for existing conversations
|
|
54
|
+
else {
|
|
55
|
+
await this.handleConversationSelection();
|
|
56
|
+
}
|
|
57
|
+
// Display session information
|
|
58
|
+
logger.always(chalk.gray(`Session ID: ${this.sessionId}`));
|
|
41
59
|
logger.always(chalk.gray(`Max sessions: ${this.conversationMemoryConfig.maxSessions}`));
|
|
42
60
|
logger.always(chalk.gray(`Max turns per session: ${this.conversationMemoryConfig.maxTurnsPerSession}\n`));
|
|
43
61
|
}
|
|
62
|
+
else {
|
|
63
|
+
// No conversation memory - just create a new session
|
|
64
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
65
|
+
logger.always(chalk.gray(`Session ID: ${this.sessionId}`));
|
|
66
|
+
}
|
|
67
|
+
// Load command history from global file
|
|
68
|
+
this.commandHistory = (await loadCommandHistory()).reverse();
|
|
44
69
|
logger.always(chalk.gray('Type "help" for a list of commands.'));
|
|
45
70
|
logger.always(chalk.gray('Type "exit", "quit", or ":q" to leave the loop.'));
|
|
46
71
|
while (this.isRunning) {
|
|
@@ -61,7 +86,7 @@ export class LoopSession {
|
|
|
61
86
|
// Save session commands to history (both memory and file)
|
|
62
87
|
if (command && command.trim()) {
|
|
63
88
|
this.commandHistory.unshift(command);
|
|
64
|
-
await
|
|
89
|
+
await saveCommandToHistory(command);
|
|
65
90
|
}
|
|
66
91
|
continue;
|
|
67
92
|
}
|
|
@@ -81,7 +106,7 @@ export class LoopSession {
|
|
|
81
106
|
// Save command to history (both memory and file)
|
|
82
107
|
if (command && command.trim()) {
|
|
83
108
|
this.commandHistory.unshift(command);
|
|
84
|
-
await
|
|
109
|
+
await saveCommandToHistory(command);
|
|
85
110
|
}
|
|
86
111
|
}
|
|
87
112
|
catch (error) {
|
|
@@ -90,8 +115,96 @@ export class LoopSession {
|
|
|
90
115
|
}
|
|
91
116
|
}
|
|
92
117
|
// Cleanup on exit
|
|
93
|
-
|
|
94
|
-
|
|
118
|
+
this.cleanup();
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Handle direct session resume from CLI option
|
|
122
|
+
*/
|
|
123
|
+
async handleDirectSessionResume(directResumeSessionId) {
|
|
124
|
+
logger.always(chalk.blue(`Attempting to resume session: ${directResumeSessionId.slice(0, 12)}...`));
|
|
125
|
+
try {
|
|
126
|
+
const restoreResult = await this.restoreSession(directResumeSessionId);
|
|
127
|
+
if (restoreResult.success) {
|
|
128
|
+
displaySessionMessage(restoreResult);
|
|
129
|
+
this.sessionId = directResumeSessionId;
|
|
130
|
+
// Display conversation preview
|
|
131
|
+
const preview = await getConversationPreview(directResumeSessionId, 2);
|
|
132
|
+
displayConversationPreview(preview, 2);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
displaySessionMessage(restoreResult);
|
|
136
|
+
logger.always(chalk.yellow("Starting new conversation instead..."));
|
|
137
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
logger.error(`Failed to resume session ${directResumeSessionId}:`, error);
|
|
142
|
+
logger.always(chalk.yellow("Starting new conversation instead..."));
|
|
143
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Handle conversation selection logic when no direct resume is specified
|
|
148
|
+
*/
|
|
149
|
+
async handleConversationSelection() {
|
|
150
|
+
logger.always(chalk.gray("Checking for existing conversations...\n"));
|
|
151
|
+
try {
|
|
152
|
+
const conversationSelector = new ConversationSelector();
|
|
153
|
+
// Check if there are any stored conversations
|
|
154
|
+
const hasStoredConversations = await conversationSelector.hasStoredConversations();
|
|
155
|
+
if (hasStoredConversations) {
|
|
156
|
+
// Show conversation selection menu
|
|
157
|
+
const selectedSessionId = await conversationSelector.displayConversationMenu();
|
|
158
|
+
if (selectedSessionId !== "NEW_CONVERSATION") {
|
|
159
|
+
// Restore the selected conversation
|
|
160
|
+
logger.always(chalk.blue("Restoring conversation..."));
|
|
161
|
+
const restoreResult = await this.restoreSession(selectedSessionId);
|
|
162
|
+
if (restoreResult.success) {
|
|
163
|
+
displaySessionMessage(restoreResult);
|
|
164
|
+
this.sessionId = selectedSessionId;
|
|
165
|
+
// Display conversation preview
|
|
166
|
+
const preview = await getConversationPreview(selectedSessionId, 2);
|
|
167
|
+
displayConversationPreview(preview, 2);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
displaySessionMessage(restoreResult);
|
|
171
|
+
logger.always(chalk.yellow("Starting new conversation instead..."));
|
|
172
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// User chose to start new conversation
|
|
177
|
+
logger.always(chalk.blue("Starting new conversation..."));
|
|
178
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// No existing conversations found
|
|
183
|
+
logger.always(chalk.gray("No existing conversations found."));
|
|
184
|
+
logger.always(chalk.blue("Starting new conversation..."));
|
|
185
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
186
|
+
}
|
|
187
|
+
// Close the conversation selector
|
|
188
|
+
await conversationSelector.close();
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
logger.warn("Failed to check for existing conversations:", error);
|
|
192
|
+
logger.always(chalk.yellow("Starting new conversation..."));
|
|
193
|
+
this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Clean up session resources and connections
|
|
198
|
+
*/
|
|
199
|
+
cleanup() {
|
|
200
|
+
try {
|
|
201
|
+
globalSession.clearLoopSession();
|
|
202
|
+
logger.always(chalk.yellow("Loop session ended."));
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
// Silently handle cleanup errors to avoid hanging
|
|
206
|
+
logger.error("Error during cleanup:", error);
|
|
207
|
+
}
|
|
95
208
|
}
|
|
96
209
|
async handleSessionCommands(command) {
|
|
97
210
|
const parts = command.split(" ");
|
|
@@ -113,7 +226,7 @@ export class LoopSession {
|
|
|
113
226
|
return true;
|
|
114
227
|
}
|
|
115
228
|
const valueStr = parts.slice(2).join(" ");
|
|
116
|
-
let value =
|
|
229
|
+
let value = parseValue(valueStr);
|
|
117
230
|
// Validate type
|
|
118
231
|
if (schema.type === "boolean" && typeof value !== "boolean") {
|
|
119
232
|
logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a boolean (true/false).`));
|
|
@@ -196,21 +309,6 @@ export class LoopSession {
|
|
|
196
309
|
return false;
|
|
197
310
|
}
|
|
198
311
|
}
|
|
199
|
-
parseValue(value) {
|
|
200
|
-
// Try to parse as number
|
|
201
|
-
if (!isNaN(Number(value))) {
|
|
202
|
-
return Number(value);
|
|
203
|
-
}
|
|
204
|
-
// Try to parse as boolean
|
|
205
|
-
if (value.toLowerCase() === "true") {
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
if (value.toLowerCase() === "false") {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
// Return as string
|
|
212
|
-
return value;
|
|
213
|
-
}
|
|
214
312
|
showHelp() {
|
|
215
313
|
logger.always(chalk.cyan("Available Loop Mode Commands:"));
|
|
216
314
|
const commands = [
|
|
@@ -254,39 +352,6 @@ export class LoopSession {
|
|
|
254
352
|
}
|
|
255
353
|
}
|
|
256
354
|
}
|
|
257
|
-
/**
|
|
258
|
-
* Load command history from the global history file
|
|
259
|
-
*/
|
|
260
|
-
async loadHistory() {
|
|
261
|
-
try {
|
|
262
|
-
const content = await fs.readFile(HISTORY_FILE, "utf8");
|
|
263
|
-
return content.split("\n").filter((line) => line.trim());
|
|
264
|
-
}
|
|
265
|
-
catch {
|
|
266
|
-
// File doesn't exist yet or can't be read
|
|
267
|
-
return [];
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Save a command to the global history file
|
|
272
|
-
*/
|
|
273
|
-
async saveCommand(command) {
|
|
274
|
-
try {
|
|
275
|
-
// Skip potentially sensitive commands
|
|
276
|
-
const sensitivePattern = /\b(api[-_]?key|token|password|secret|authorization)\b/i;
|
|
277
|
-
if (sensitivePattern.test(command)) {
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
// Use writeFile with flag 'a' and mode 0o600 to ensure permissions on creation
|
|
281
|
-
await fs.writeFile(HISTORY_FILE, command + "\n", { flag: "a", mode: 0o600 });
|
|
282
|
-
// Ensure existing file remains private (best-effort)
|
|
283
|
-
await fs.chmod(HISTORY_FILE, 0o600);
|
|
284
|
-
}
|
|
285
|
-
catch (error) {
|
|
286
|
-
// Log file write errors as warnings, but do not interrupt CLI flow
|
|
287
|
-
logger.warn("Warning: Could not save command to history:", error);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
355
|
/**
|
|
291
356
|
* Get command input with history support using readline
|
|
292
357
|
*/
|
|
@@ -310,4 +375,135 @@ export class LoopSession {
|
|
|
310
375
|
});
|
|
311
376
|
});
|
|
312
377
|
}
|
|
378
|
+
// === SESSION RESTORATION METHODS ===
|
|
379
|
+
/**
|
|
380
|
+
* Restore a conversation session and set up the global session state
|
|
381
|
+
*/
|
|
382
|
+
async restoreSession(sessionId, userId) {
|
|
383
|
+
// Local helper for creating failure results with bound sessionId
|
|
384
|
+
const createFailure = (error) => ({
|
|
385
|
+
success: false,
|
|
386
|
+
sessionId,
|
|
387
|
+
messageCount: 0,
|
|
388
|
+
error,
|
|
389
|
+
});
|
|
390
|
+
try {
|
|
391
|
+
logger.debug(`Attempting to restore session: ${sessionId}`);
|
|
392
|
+
// 1. Create NeuroLink instance and validate conversation in one step
|
|
393
|
+
const { neurolinkInstance, conversationData } = await this.createAndValidateNeurolinkInstance(sessionId, userId);
|
|
394
|
+
if (!conversationData) {
|
|
395
|
+
return createFailure(`Conversation ${sessionId} not found or inaccessible`);
|
|
396
|
+
}
|
|
397
|
+
// 2. Set up tool execution context
|
|
398
|
+
await this.configureToolContext(neurolinkInstance, sessionId, userId);
|
|
399
|
+
// 3. Restore global session state
|
|
400
|
+
this.restoreGlobalSessionState(sessionId, neurolinkInstance, conversationData);
|
|
401
|
+
// 4. Verify conversation context accessibility
|
|
402
|
+
await verifyConversationContext(sessionId);
|
|
403
|
+
const result = {
|
|
404
|
+
success: true,
|
|
405
|
+
sessionId,
|
|
406
|
+
messageCount: conversationData.messages?.length || 0,
|
|
407
|
+
lastActivity: conversationData.updatedAt,
|
|
408
|
+
};
|
|
409
|
+
logger.info(`Session restored successfully: ${sessionId}`, {
|
|
410
|
+
messageCount: result.messageCount,
|
|
411
|
+
lastActivity: result.lastActivity,
|
|
412
|
+
});
|
|
413
|
+
return result;
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
logger.error(`Failed to restore session ${sessionId}:`, error);
|
|
417
|
+
return createFailure(error instanceof Error ? error.message : String(error));
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Create NeuroLink instance and validate conversation in one step
|
|
422
|
+
* Eliminates redundant instance creation and initialization
|
|
423
|
+
*/
|
|
424
|
+
async createAndValidateNeurolinkInstance(sessionId, userId) {
|
|
425
|
+
// Create NeuroLink instance with proper configuration
|
|
426
|
+
const neurolinkOptions = {};
|
|
427
|
+
if (this.conversationMemoryConfig?.enabled) {
|
|
428
|
+
neurolinkOptions.conversationMemory = {
|
|
429
|
+
enabled: true,
|
|
430
|
+
maxSessions: this.conversationMemoryConfig.maxSessions,
|
|
431
|
+
maxTurnsPerSession: this.conversationMemoryConfig.maxTurnsPerSession,
|
|
432
|
+
};
|
|
433
|
+
neurolinkOptions.sessionId = sessionId;
|
|
434
|
+
}
|
|
435
|
+
const neurolinkInstance = new NeuroLink(neurolinkOptions);
|
|
436
|
+
await neurolinkInstance.ensureConversationMemoryInitialized();
|
|
437
|
+
// Use the same instance to validate conversation exists
|
|
438
|
+
try {
|
|
439
|
+
const messages = await neurolinkInstance.getConversationHistory(sessionId);
|
|
440
|
+
if (!messages || messages.length === 0) {
|
|
441
|
+
logger.debug(`No conversation messages found for session ${sessionId}`);
|
|
442
|
+
return { neurolinkInstance, conversationData: null };
|
|
443
|
+
}
|
|
444
|
+
// Create conversation object with available data
|
|
445
|
+
const conversationData = {
|
|
446
|
+
id: sessionId,
|
|
447
|
+
sessionId,
|
|
448
|
+
userId: userId || "unknown",
|
|
449
|
+
messages,
|
|
450
|
+
createdAt: new Date().toISOString(), // Fallback
|
|
451
|
+
updatedAt: new Date().toISOString(), // Fallback
|
|
452
|
+
title: messages[0]?.content?.slice(0, 50) + "..." || "Untitled Conversation",
|
|
453
|
+
};
|
|
454
|
+
return { neurolinkInstance, conversationData };
|
|
455
|
+
}
|
|
456
|
+
catch (error) {
|
|
457
|
+
logger.debug(`Error accessing conversation for session ${sessionId}:`, error);
|
|
458
|
+
return { neurolinkInstance, conversationData: null };
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* Configure tool execution context for the restored session
|
|
463
|
+
*/
|
|
464
|
+
async configureToolContext(neurolinkInstance, sessionId, userId) {
|
|
465
|
+
const toolContext = {
|
|
466
|
+
sessionId,
|
|
467
|
+
userId: userId || "loop-user",
|
|
468
|
+
source: "loop-mode",
|
|
469
|
+
restored: true,
|
|
470
|
+
timestamp: new Date().toISOString(),
|
|
471
|
+
};
|
|
472
|
+
neurolinkInstance.setToolContext(toolContext);
|
|
473
|
+
logger.debug("Tool execution context configured for restored session", {
|
|
474
|
+
sessionId,
|
|
475
|
+
userId,
|
|
476
|
+
hasToolContext: true,
|
|
477
|
+
});
|
|
478
|
+
await this.verifyToolAvailability(neurolinkInstance);
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Verify that tools are available and working in the restored session
|
|
482
|
+
*/
|
|
483
|
+
async verifyToolAvailability(neurolinkInstance) {
|
|
484
|
+
try {
|
|
485
|
+
const availableTools = await neurolinkInstance.getAllAvailableTools();
|
|
486
|
+
logger.debug(`Tools available in restored session: ${availableTools.length} tools`, {
|
|
487
|
+
toolNames: availableTools.slice(0, 5).map((t) => t.name),
|
|
488
|
+
hasFileTools: availableTools.some((t) => t.name.includes("file") || t.name.includes("File")),
|
|
489
|
+
hasDirectoryTools: availableTools.some((t) => t.name.includes("directory") || t.name.includes("Directory")),
|
|
490
|
+
});
|
|
491
|
+
if (availableTools.length === 0) {
|
|
492
|
+
logger.warn("No tools available in restored session - this may affect AI capabilities");
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
catch (error) {
|
|
496
|
+
logger.warn("Could not verify tool availability in restored session:", error);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
/**
|
|
500
|
+
* Restore global session state and session variables
|
|
501
|
+
*/
|
|
502
|
+
restoreGlobalSessionState(sessionId, neurolinkInstance, conversationData) {
|
|
503
|
+
globalSession.clearLoopSession();
|
|
504
|
+
globalSession.restoreLoopSession(sessionId, neurolinkInstance, this.conversationMemoryConfig, {});
|
|
505
|
+
if (conversationData) {
|
|
506
|
+
restoreSessionVariables(conversationData);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
313
509
|
}
|
|
@@ -98,6 +98,7 @@ export class BaseProvider {
|
|
|
98
98
|
// Convert stream options to text generation options
|
|
99
99
|
const textOptions = {
|
|
100
100
|
prompt: options.input?.text || "",
|
|
101
|
+
input: options.input,
|
|
101
102
|
systemPrompt: options.systemPrompt,
|
|
102
103
|
temperature: options.temperature,
|
|
103
104
|
maxTokens: options.maxTokens,
|
|
@@ -111,6 +112,7 @@ export class BaseProvider {
|
|
|
111
112
|
evaluationDomain: options.evaluationDomain,
|
|
112
113
|
toolUsageContext: options.toolUsageContext,
|
|
113
114
|
context: options.context,
|
|
115
|
+
csvOptions: options.csvOptions,
|
|
114
116
|
};
|
|
115
117
|
logger.debug(`Calling generate for fake streaming`, {
|
|
116
118
|
provider: this.providerName,
|
|
@@ -229,7 +231,9 @@ export class BaseProvider {
|
|
|
229
231
|
const input = opts.input;
|
|
230
232
|
const hasImages = !!input?.images?.length;
|
|
231
233
|
const hasContent = !!input?.content?.length;
|
|
232
|
-
|
|
234
|
+
const hasCSVFiles = !!input?.csvFiles?.length;
|
|
235
|
+
const hasFiles = !!input?.files?.length;
|
|
236
|
+
return hasImages || hasContent || hasCSVFiles || hasFiles;
|
|
233
237
|
};
|
|
234
238
|
let messages;
|
|
235
239
|
if (hasMultimodalInput(options)) {
|
|
@@ -242,7 +246,10 @@ export class BaseProvider {
|
|
|
242
246
|
text: options.prompt || options.input?.text || "",
|
|
243
247
|
images: input?.images,
|
|
244
248
|
content: input?.content,
|
|
249
|
+
csvFiles: input?.csvFiles,
|
|
250
|
+
files: input?.files,
|
|
245
251
|
},
|
|
252
|
+
csvOptions: options.csvOptions,
|
|
246
253
|
provider: options.provider,
|
|
247
254
|
model: options.model,
|
|
248
255
|
temperature: options.temperature,
|
|
@@ -258,7 +265,7 @@ export class BaseProvider {
|
|
|
258
265
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
259
266
|
logger.debug("No multimodal input detected, using standard message builder");
|
|
260
267
|
}
|
|
261
|
-
messages = buildMessagesArray(options);
|
|
268
|
+
messages = await buildMessagesArray(options);
|
|
262
269
|
}
|
|
263
270
|
// Convert messages to Vercel AI SDK format
|
|
264
271
|
return messages.map((msg) => {
|
package/dist/core/evaluation.js
CHANGED
|
@@ -225,8 +225,11 @@ Completeness: [score]
|
|
|
225
225
|
Overall: [score]
|
|
226
226
|
Reasoning: [Provide a detailed explanation of your evaluation, explaining why you gave these scores. Include specific observations about the response's strengths and all possible areas for improvement.]
|
|
227
227
|
`;
|
|
228
|
-
// Generate evaluation
|
|
229
|
-
const result = await provider.generate(
|
|
228
|
+
// Generate evaluation (simple text prompt only - no file processing)
|
|
229
|
+
const result = await provider.generate({
|
|
230
|
+
input: { text: prompt },
|
|
231
|
+
disableTools: true, // Evaluation doesn't need tools
|
|
232
|
+
});
|
|
230
233
|
if (!result) {
|
|
231
234
|
logger.debug(`[${functionTag}] No response from provider`);
|
|
232
235
|
return getDefaultEvaluation("no-response", Date.now() - startTime, context);
|
|
@@ -45,9 +45,9 @@ export class ProviderRegistry {
|
|
|
45
45
|
}, undefined, // Let provider read BEDROCK_MODEL from .env
|
|
46
46
|
["bedrock", "aws"]);
|
|
47
47
|
// Register Azure OpenAI provider
|
|
48
|
-
ProviderFactory.registerProvider(AIProviderName.AZURE, async (modelName) => {
|
|
48
|
+
ProviderFactory.registerProvider(AIProviderName.AZURE, async (modelName, _providerName, sdk) => {
|
|
49
49
|
const { AzureOpenAIProvider } = await import("../providers/azureOpenai.js");
|
|
50
|
-
return new AzureOpenAIProvider(modelName);
|
|
50
|
+
return new AzureOpenAIProvider(modelName, sdk);
|
|
51
51
|
}, process.env.AZURE_MODEL ||
|
|
52
52
|
process.env.AZURE_OPENAI_MODEL ||
|
|
53
53
|
process.env.AZURE_OPENAI_DEPLOYMENT ||
|
|
@@ -346,6 +346,61 @@ export declare const directAgentTools: {
|
|
|
346
346
|
count?: undefined;
|
|
347
347
|
}>;
|
|
348
348
|
};
|
|
349
|
+
analyzeCSV: import("ai").Tool<z.ZodObject<{
|
|
350
|
+
filePath: z.ZodEffects<z.ZodString, string, string>;
|
|
351
|
+
operation: z.ZodEnum<["count_by_column", "sum_by_column", "average_by_column", "min_max_by_column", "describe"]>;
|
|
352
|
+
column: z.ZodOptional<z.ZodString>;
|
|
353
|
+
maxRows: z.ZodOptional<z.ZodNumber>;
|
|
354
|
+
}, "strip", z.ZodTypeAny, {
|
|
355
|
+
filePath: string;
|
|
356
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
357
|
+
maxRows?: number | undefined;
|
|
358
|
+
column?: string | undefined;
|
|
359
|
+
}, {
|
|
360
|
+
filePath: string;
|
|
361
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
362
|
+
maxRows?: number | undefined;
|
|
363
|
+
column?: string | undefined;
|
|
364
|
+
}>, {
|
|
365
|
+
success: boolean;
|
|
366
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
367
|
+
column: string | undefined;
|
|
368
|
+
result: string;
|
|
369
|
+
rowCount: number;
|
|
370
|
+
} | {
|
|
371
|
+
success: boolean;
|
|
372
|
+
error: string;
|
|
373
|
+
operation?: undefined;
|
|
374
|
+
column?: undefined;
|
|
375
|
+
} | {
|
|
376
|
+
success: boolean;
|
|
377
|
+
error: string;
|
|
378
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
379
|
+
column: string | undefined;
|
|
380
|
+
}> & {
|
|
381
|
+
execute: (args: {
|
|
382
|
+
filePath: string;
|
|
383
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
384
|
+
maxRows?: number | undefined;
|
|
385
|
+
column?: string | undefined;
|
|
386
|
+
}, options: import("ai").ToolExecutionOptions) => PromiseLike<{
|
|
387
|
+
success: boolean;
|
|
388
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
389
|
+
column: string | undefined;
|
|
390
|
+
result: string;
|
|
391
|
+
rowCount: number;
|
|
392
|
+
} | {
|
|
393
|
+
success: boolean;
|
|
394
|
+
error: string;
|
|
395
|
+
operation?: undefined;
|
|
396
|
+
column?: undefined;
|
|
397
|
+
} | {
|
|
398
|
+
success: boolean;
|
|
399
|
+
error: string;
|
|
400
|
+
operation: "count_by_column" | "sum_by_column" | "average_by_column" | "min_max_by_column" | "describe";
|
|
401
|
+
column: string | undefined;
|
|
402
|
+
}>;
|
|
403
|
+
};
|
|
349
404
|
websearchGrounding: import("ai").Tool<z.ZodObject<{
|
|
350
405
|
query: z.ZodString;
|
|
351
406
|
maxResults: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|