@juspay/neurolink 7.48.0 → 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.
Files changed (156) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +177 -784
  3. package/dist/agent/directTools.d.ts +55 -0
  4. package/dist/agent/directTools.js +266 -0
  5. package/dist/cli/factories/commandFactory.d.ts +2 -0
  6. package/dist/cli/factories/commandFactory.js +130 -16
  7. package/dist/cli/index.js +0 -0
  8. package/dist/cli/loop/conversationSelector.d.ts +45 -0
  9. package/dist/cli/loop/conversationSelector.js +222 -0
  10. package/dist/cli/loop/optionsSchema.d.ts +1 -1
  11. package/dist/cli/loop/session.d.ts +36 -8
  12. package/dist/cli/loop/session.js +257 -61
  13. package/dist/core/baseProvider.js +9 -2
  14. package/dist/core/evaluation.js +5 -2
  15. package/dist/factories/providerRegistry.js +2 -2
  16. package/dist/lib/agent/directTools.d.ts +55 -0
  17. package/dist/lib/agent/directTools.js +266 -0
  18. package/dist/lib/core/baseProvider.js +9 -2
  19. package/dist/lib/core/evaluation.js +5 -2
  20. package/dist/lib/factories/providerRegistry.js +2 -2
  21. package/dist/lib/mcp/factory.d.ts +2 -157
  22. package/dist/lib/mcp/flexibleToolValidator.d.ts +1 -5
  23. package/dist/lib/mcp/index.d.ts +3 -2
  24. package/dist/lib/mcp/mcpCircuitBreaker.d.ts +1 -75
  25. package/dist/lib/mcp/mcpClientFactory.d.ts +1 -20
  26. package/dist/lib/mcp/mcpClientFactory.js +1 -0
  27. package/dist/lib/mcp/registry.d.ts +3 -10
  28. package/dist/lib/mcp/servers/agent/directToolsServer.d.ts +1 -1
  29. package/dist/lib/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
  30. package/dist/lib/mcp/servers/utilities/utilityServer.d.ts +1 -1
  31. package/dist/lib/mcp/toolDiscoveryService.d.ts +3 -84
  32. package/dist/lib/mcp/toolRegistry.d.ts +2 -24
  33. package/dist/lib/middleware/builtin/guardrails.d.ts +5 -16
  34. package/dist/lib/middleware/builtin/guardrails.js +44 -39
  35. package/dist/lib/middleware/utils/guardrailsUtils.d.ts +64 -0
  36. package/dist/lib/middleware/utils/guardrailsUtils.js +387 -0
  37. package/dist/lib/neurolink.d.ts +1 -1
  38. package/dist/lib/providers/anthropic.js +46 -3
  39. package/dist/lib/providers/azureOpenai.js +8 -2
  40. package/dist/lib/providers/googleAiStudio.js +8 -2
  41. package/dist/lib/providers/googleVertex.js +11 -2
  42. package/dist/lib/providers/huggingFace.js +1 -1
  43. package/dist/lib/providers/litellm.js +1 -1
  44. package/dist/lib/providers/mistral.js +1 -1
  45. package/dist/lib/providers/openAI.js +46 -3
  46. package/dist/lib/providers/sagemaker/adaptive-semaphore.d.ts +1 -13
  47. package/dist/lib/providers/sagemaker/client.d.ts +1 -1
  48. package/dist/lib/providers/sagemaker/config.d.ts +1 -1
  49. package/dist/lib/providers/sagemaker/detection.d.ts +1 -1
  50. package/dist/lib/providers/sagemaker/errors.d.ts +1 -1
  51. package/dist/lib/providers/sagemaker/index.d.ts +1 -1
  52. package/dist/lib/providers/sagemaker/language-model.d.ts +1 -1
  53. package/dist/lib/providers/sagemaker/parsers.d.ts +1 -1
  54. package/dist/lib/providers/sagemaker/streaming.d.ts +1 -1
  55. package/dist/lib/providers/sagemaker/structured-parser.d.ts +1 -1
  56. package/dist/lib/session/globalSessionState.d.ts +26 -0
  57. package/dist/lib/session/globalSessionState.js +49 -0
  58. package/dist/lib/types/cli.d.ts +28 -0
  59. package/dist/lib/types/content.d.ts +18 -5
  60. package/dist/lib/types/contextTypes.d.ts +1 -1
  61. package/dist/lib/types/conversation.d.ts +55 -4
  62. package/dist/lib/types/fileTypes.d.ts +65 -0
  63. package/dist/lib/types/fileTypes.js +4 -0
  64. package/dist/lib/types/generateTypes.d.ts +12 -0
  65. package/dist/lib/types/guardrails.d.ts +103 -0
  66. package/dist/lib/types/guardrails.js +1 -0
  67. package/dist/lib/types/index.d.ts +4 -2
  68. package/dist/lib/types/index.js +4 -0
  69. package/dist/lib/types/mcpTypes.d.ts +407 -14
  70. package/dist/lib/types/providers.d.ts +469 -0
  71. package/dist/lib/types/streamTypes.d.ts +7 -0
  72. package/dist/lib/types/tools.d.ts +132 -35
  73. package/dist/lib/utils/csvProcessor.d.ts +68 -0
  74. package/dist/lib/utils/csvProcessor.js +277 -0
  75. package/dist/lib/utils/fileDetector.d.ts +57 -0
  76. package/dist/lib/utils/fileDetector.js +457 -0
  77. package/dist/lib/utils/imageProcessor.d.ts +10 -0
  78. package/dist/lib/utils/imageProcessor.js +22 -0
  79. package/dist/lib/utils/loopUtils.d.ts +71 -0
  80. package/dist/lib/utils/loopUtils.js +262 -0
  81. package/dist/lib/utils/messageBuilder.d.ts +2 -1
  82. package/dist/lib/utils/messageBuilder.js +197 -2
  83. package/dist/lib/utils/optionsUtils.d.ts +1 -1
  84. package/dist/mcp/factory.d.ts +2 -157
  85. package/dist/mcp/flexibleToolValidator.d.ts +1 -5
  86. package/dist/mcp/index.d.ts +3 -2
  87. package/dist/mcp/mcpCircuitBreaker.d.ts +1 -75
  88. package/dist/mcp/mcpClientFactory.d.ts +1 -20
  89. package/dist/mcp/mcpClientFactory.js +1 -0
  90. package/dist/mcp/registry.d.ts +3 -10
  91. package/dist/mcp/servers/agent/directToolsServer.d.ts +1 -1
  92. package/dist/mcp/servers/aiProviders/aiCoreServer.d.ts +1 -1
  93. package/dist/mcp/servers/utilities/utilityServer.d.ts +1 -1
  94. package/dist/mcp/toolDiscoveryService.d.ts +3 -84
  95. package/dist/mcp/toolRegistry.d.ts +2 -24
  96. package/dist/middleware/builtin/guardrails.d.ts +5 -16
  97. package/dist/middleware/builtin/guardrails.js +44 -39
  98. package/dist/middleware/utils/guardrailsUtils.d.ts +64 -0
  99. package/dist/middleware/utils/guardrailsUtils.js +387 -0
  100. package/dist/neurolink.d.ts +1 -1
  101. package/dist/providers/anthropic.js +46 -3
  102. package/dist/providers/azureOpenai.js +8 -2
  103. package/dist/providers/googleAiStudio.js +8 -2
  104. package/dist/providers/googleVertex.js +11 -2
  105. package/dist/providers/huggingFace.js +1 -1
  106. package/dist/providers/litellm.js +1 -1
  107. package/dist/providers/mistral.js +1 -1
  108. package/dist/providers/openAI.js +46 -3
  109. package/dist/providers/sagemaker/adaptive-semaphore.d.ts +1 -13
  110. package/dist/providers/sagemaker/client.d.ts +1 -1
  111. package/dist/providers/sagemaker/config.d.ts +1 -1
  112. package/dist/providers/sagemaker/detection.d.ts +1 -1
  113. package/dist/providers/sagemaker/errors.d.ts +1 -1
  114. package/dist/providers/sagemaker/index.d.ts +1 -1
  115. package/dist/providers/sagemaker/language-model.d.ts +3 -3
  116. package/dist/providers/sagemaker/parsers.d.ts +1 -1
  117. package/dist/providers/sagemaker/streaming.d.ts +1 -1
  118. package/dist/providers/sagemaker/structured-parser.d.ts +1 -1
  119. package/dist/session/globalSessionState.d.ts +26 -0
  120. package/dist/session/globalSessionState.js +49 -0
  121. package/dist/types/cli.d.ts +28 -0
  122. package/dist/types/content.d.ts +18 -5
  123. package/dist/types/contextTypes.d.ts +1 -1
  124. package/dist/types/conversation.d.ts +55 -4
  125. package/dist/types/fileTypes.d.ts +65 -0
  126. package/dist/types/fileTypes.js +4 -0
  127. package/dist/types/generateTypes.d.ts +12 -0
  128. package/dist/types/guardrails.d.ts +103 -0
  129. package/dist/types/guardrails.js +1 -0
  130. package/dist/types/index.d.ts +4 -2
  131. package/dist/types/index.js +4 -0
  132. package/dist/types/mcpTypes.d.ts +407 -14
  133. package/dist/types/modelTypes.d.ts +6 -6
  134. package/dist/types/providers.d.ts +469 -0
  135. package/dist/types/streamTypes.d.ts +7 -0
  136. package/dist/types/tools.d.ts +132 -35
  137. package/dist/utils/csvProcessor.d.ts +68 -0
  138. package/dist/utils/csvProcessor.js +277 -0
  139. package/dist/utils/fileDetector.d.ts +57 -0
  140. package/dist/utils/fileDetector.js +457 -0
  141. package/dist/utils/imageProcessor.d.ts +10 -0
  142. package/dist/utils/imageProcessor.js +22 -0
  143. package/dist/utils/loopUtils.d.ts +71 -0
  144. package/dist/utils/loopUtils.js +262 -0
  145. package/dist/utils/messageBuilder.d.ts +2 -1
  146. package/dist/utils/messageBuilder.js +197 -2
  147. package/dist/utils/optionsUtils.d.ts +1 -1
  148. package/package.json +9 -3
  149. package/dist/lib/mcp/contracts/mcpContract.d.ts +0 -106
  150. package/dist/lib/mcp/contracts/mcpContract.js +0 -5
  151. package/dist/lib/providers/sagemaker/types.d.ts +0 -456
  152. package/dist/lib/providers/sagemaker/types.js +0 -7
  153. package/dist/mcp/contracts/mcpContract.d.ts +0 -106
  154. package/dist/mcp/contracts/mcpContract.js +0 -5
  155. package/dist/providers/sagemaker/types.d.ts +0 -456
  156. package/dist/providers/sagemaker/types.js +0 -7
@@ -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 this.loadHistory()).reverse();
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 this.saveCommand(command);
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 this.saveCommand(command);
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
- globalSession.clearLoopSession();
94
- logger.always(chalk.yellow("Loop session ended."));
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 = this.parseValue(valueStr);
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
- return hasImages || hasContent;
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) => {
@@ -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(prompt);
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>>;