@juspay/neurolink 7.33.4 → 7.35.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 (115) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +101 -7
  3. package/dist/cli/commands/setup-anthropic.d.ts +16 -0
  4. package/dist/cli/commands/setup-anthropic.js +414 -0
  5. package/dist/cli/commands/setup-azure.d.ts +17 -0
  6. package/dist/cli/commands/setup-azure.js +415 -0
  7. package/dist/cli/commands/setup-bedrock.d.ts +13 -0
  8. package/dist/cli/commands/setup-bedrock.js +487 -0
  9. package/dist/cli/commands/setup-gcp.d.ts +18 -0
  10. package/dist/cli/commands/setup-gcp.js +569 -0
  11. package/dist/cli/commands/setup-google-ai.d.ts +16 -0
  12. package/dist/cli/commands/setup-google-ai.js +369 -0
  13. package/dist/cli/commands/setup-huggingface.d.ts +8 -0
  14. package/dist/cli/commands/setup-huggingface.js +200 -0
  15. package/dist/cli/commands/setup-mistral.d.ts +8 -0
  16. package/dist/cli/commands/setup-mistral.js +233 -0
  17. package/dist/cli/commands/setup-openai.d.ts +16 -0
  18. package/dist/cli/commands/setup-openai.js +402 -0
  19. package/dist/cli/commands/setup.d.ts +19 -0
  20. package/dist/cli/commands/setup.js +539 -0
  21. package/dist/cli/errorHandler.d.ts +1 -0
  22. package/dist/cli/errorHandler.js +28 -0
  23. package/dist/cli/factories/commandFactory.d.ts +27 -0
  24. package/dist/cli/factories/commandFactory.js +416 -60
  25. package/dist/cli/factories/ollamaCommandFactory.js +7 -1
  26. package/dist/cli/factories/setupCommandFactory.d.ts +18 -0
  27. package/dist/cli/factories/setupCommandFactory.js +137 -0
  28. package/dist/cli/index.d.ts +1 -1
  29. package/dist/cli/index.js +9 -164
  30. package/dist/cli/loop/optionsSchema.d.ts +15 -0
  31. package/dist/cli/loop/optionsSchema.js +59 -0
  32. package/dist/cli/loop/session.d.ts +15 -0
  33. package/dist/cli/loop/session.js +252 -0
  34. package/dist/cli/parser.d.ts +1 -0
  35. package/dist/cli/parser.js +161 -0
  36. package/dist/cli/utils/envManager.d.ts +3 -2
  37. package/dist/cli/utils/envManager.js +18 -4
  38. package/dist/cli/utils/ollamaUtils.js +6 -0
  39. package/dist/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
  40. package/dist/core/baseProvider.js +17 -3
  41. package/dist/core/conversationMemoryFactory.d.ts +23 -0
  42. package/dist/core/conversationMemoryFactory.js +144 -0
  43. package/dist/core/conversationMemoryInitializer.d.ts +14 -0
  44. package/dist/core/conversationMemoryInitializer.js +127 -0
  45. package/dist/core/conversationMemoryManager.d.ts +3 -2
  46. package/dist/core/conversationMemoryManager.js +4 -3
  47. package/dist/core/redisConversationMemoryManager.d.ts +73 -0
  48. package/dist/core/redisConversationMemoryManager.js +483 -0
  49. package/dist/core/types.d.ts +1 -1
  50. package/dist/lib/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
  51. package/dist/lib/core/baseProvider.js +17 -3
  52. package/dist/lib/core/conversationMemoryFactory.d.ts +23 -0
  53. package/dist/lib/core/conversationMemoryFactory.js +144 -0
  54. package/dist/lib/core/conversationMemoryInitializer.d.ts +14 -0
  55. package/dist/lib/core/conversationMemoryInitializer.js +127 -0
  56. package/dist/lib/core/conversationMemoryManager.d.ts +3 -2
  57. package/dist/lib/core/conversationMemoryManager.js +4 -3
  58. package/dist/lib/core/redisConversationMemoryManager.d.ts +73 -0
  59. package/dist/lib/core/redisConversationMemoryManager.js +483 -0
  60. package/dist/lib/core/types.d.ts +1 -1
  61. package/dist/lib/neurolink.d.ts +15 -9
  62. package/dist/lib/neurolink.js +218 -67
  63. package/dist/lib/providers/amazonBedrock.d.ts +4 -4
  64. package/dist/lib/providers/anthropic.d.ts +4 -4
  65. package/dist/lib/providers/azureOpenai.d.ts +4 -4
  66. package/dist/lib/providers/googleAiStudio.d.ts +4 -4
  67. package/dist/lib/providers/googleAiStudio.js +1 -1
  68. package/dist/lib/providers/huggingFace.d.ts +4 -4
  69. package/dist/lib/providers/litellm.d.ts +1 -1
  70. package/dist/lib/providers/mistral.d.ts +4 -4
  71. package/dist/lib/providers/mistral.js +2 -2
  72. package/dist/lib/providers/openAI.d.ts +4 -4
  73. package/dist/lib/session/globalSessionState.d.ts +27 -0
  74. package/dist/lib/session/globalSessionState.js +77 -0
  75. package/dist/lib/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
  76. package/dist/lib/types/generateTypes.d.ts +1 -1
  77. package/dist/lib/types/streamTypes.d.ts +1 -1
  78. package/dist/lib/utils/conversationMemory.d.ts +22 -0
  79. package/dist/lib/utils/conversationMemory.js +121 -0
  80. package/dist/lib/utils/conversationMemoryUtils.d.ts +1 -1
  81. package/dist/lib/utils/conversationMemoryUtils.js +2 -2
  82. package/dist/lib/utils/messageBuilder.d.ts +1 -1
  83. package/dist/lib/utils/messageBuilder.js +1 -1
  84. package/dist/lib/utils/redis.d.ts +42 -0
  85. package/dist/lib/utils/redis.js +263 -0
  86. package/dist/neurolink.d.ts +15 -9
  87. package/dist/neurolink.js +218 -67
  88. package/dist/providers/amazonBedrock.d.ts +4 -4
  89. package/dist/providers/anthropic.d.ts +4 -4
  90. package/dist/providers/azureOpenai.d.ts +4 -4
  91. package/dist/providers/googleAiStudio.d.ts +4 -4
  92. package/dist/providers/googleAiStudio.js +1 -1
  93. package/dist/providers/huggingFace.d.ts +4 -4
  94. package/dist/providers/litellm.d.ts +1 -1
  95. package/dist/providers/mistral.d.ts +4 -4
  96. package/dist/providers/mistral.js +2 -2
  97. package/dist/providers/openAI.d.ts +4 -4
  98. package/dist/session/globalSessionState.d.ts +27 -0
  99. package/dist/session/globalSessionState.js +77 -0
  100. package/dist/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
  101. package/dist/types/generateTypes.d.ts +1 -1
  102. package/dist/types/streamTypes.d.ts +1 -1
  103. package/dist/utils/conversationMemory.d.ts +22 -0
  104. package/dist/utils/conversationMemory.js +121 -0
  105. package/dist/utils/conversationMemoryUtils.d.ts +1 -1
  106. package/dist/utils/conversationMemoryUtils.js +2 -2
  107. package/dist/utils/messageBuilder.d.ts +1 -1
  108. package/dist/utils/messageBuilder.js +1 -1
  109. package/dist/utils/redis.d.ts +42 -0
  110. package/dist/utils/redis.js +263 -0
  111. package/package.json +3 -1
  112. /package/dist/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
  113. /package/dist/lib/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
  114. /package/dist/lib/types/{conversationTypes.js → conversation.js} +0 -0
  115. /package/dist/types/{conversationTypes.js → conversation.js} +0 -0
@@ -0,0 +1,252 @@
1
+ import inquirer from "inquirer";
2
+ import chalk from "chalk";
3
+ import { logger } from "../../lib/utils/logger.js";
4
+ import { globalSession } from "../../lib/session/globalSessionState.js";
5
+ import { textGenerationOptionsSchema } from "./optionsSchema.js";
6
+ import { handleError } from "../errorHandler.js";
7
+ // Banner Art
8
+ const NEUROLINK_BANNER = `
9
+ ▗▖ ▗▖▗▄▄▄▖▗▖ ▗▖▗▄▄▖ ▗▄▖ ▗▖ ▗▄▄▄▖▗▖ ▗▖▗▖ ▗▖
10
+ ▐▛▚▖▐▌▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌▐▌ █ ▐▛▚▖▐▌▐▌▗▞▘
11
+ ▐▌ ▝▜▌▐▛▀▀▘▐▌ ▐▌▐▛▀▚▖▐▌ ▐▌▐▌ █ ▐▌ ▝▜▌▐▛▚▖
12
+ ▐▌ ▐▌▐▙▄▄▖▝▚▄▞▘▐▌ ▐▌▝▚▄▞▘▐▙▄▄▖▗▄█▄▖▐▌ ▐▌▐▌ ▐▌
13
+ `;
14
+ export class LoopSession {
15
+ conversationMemoryConfig;
16
+ initializeCliParser;
17
+ isRunning = false;
18
+ sessionId;
19
+ sessionVariablesSchema = textGenerationOptionsSchema;
20
+ constructor(initializeCliParser, conversationMemoryConfig) {
21
+ this.conversationMemoryConfig = conversationMemoryConfig;
22
+ this.initializeCliParser = initializeCliParser;
23
+ }
24
+ async start() {
25
+ // Initialize global session state
26
+ this.sessionId = globalSession.setLoopSession(this.conversationMemoryConfig);
27
+ this.isRunning = true;
28
+ logger.always(chalk.bold.green(NEUROLINK_BANNER));
29
+ logger.always(chalk.bold.green("Welcome to NeuroLink Loop Mode!"));
30
+ if (this.conversationMemoryConfig?.enabled) {
31
+ logger.always(chalk.gray(`Session ID: ${this.sessionId}`));
32
+ logger.always(chalk.gray("Conversation memory enabled"));
33
+ logger.always(chalk.gray(`Max sessions: ${this.conversationMemoryConfig.maxSessions}`));
34
+ logger.always(chalk.gray(`Max turns per session: ${this.conversationMemoryConfig.maxTurnsPerSession}\n`));
35
+ }
36
+ logger.always(chalk.gray('Type "help" for a list of commands.'));
37
+ logger.always(chalk.gray('Type "exit", "quit", or ":q" to leave the loop.'));
38
+ while (this.isRunning) {
39
+ try {
40
+ const answers = await inquirer
41
+ .prompt([
42
+ {
43
+ type: "input",
44
+ name: "command",
45
+ message: chalk.blue.bold("neurolink"),
46
+ prefix: chalk.blue.green("⎔"),
47
+ suffix: chalk.blue.green(" »"),
48
+ },
49
+ ])
50
+ .catch(() => {
51
+ // This catch block handles the interruption of inquirer
52
+ return { command: "" };
53
+ });
54
+ const command = answers.command.trim();
55
+ if (command.toLowerCase() === "exit" ||
56
+ command.toLowerCase() === "quit" ||
57
+ command.toLowerCase() === ":q") {
58
+ this.isRunning = false;
59
+ continue;
60
+ }
61
+ if (!command) {
62
+ continue;
63
+ }
64
+ // Handle session variable commands first
65
+ if (await this.handleSessionCommands(command)) {
66
+ continue;
67
+ }
68
+ // Execute the command
69
+ // The .fail() handler in cli.ts is now session-aware and will
70
+ // handle all parsing and validation errors without exiting the loop.
71
+ // We create a fresh instance for each command to prevent state pollution.
72
+ const yargsInstance = this.initializeCliParser();
73
+ await yargsInstance
74
+ .scriptName("")
75
+ .fail((msg, err) => {
76
+ // Re-throw the error to be caught by the outer catch block
77
+ throw err || new Error(msg);
78
+ })
79
+ .exitProcess(false)
80
+ .parse(command);
81
+ }
82
+ catch (error) {
83
+ // Catch errors from the main loop (e.g., inquirer prompt itself failing)
84
+ handleError(error, "An unexpected error occurred");
85
+ }
86
+ }
87
+ // Cleanup on exit
88
+ globalSession.clearLoopSession();
89
+ logger.always(chalk.yellow("Loop session ended."));
90
+ }
91
+ async handleSessionCommands(command) {
92
+ const parts = command.split(" ");
93
+ const cmd = parts[0].toLowerCase();
94
+ switch (cmd) {
95
+ case "help":
96
+ this.showHelp();
97
+ return true;
98
+ case "set":
99
+ if (parts.length === 2 && parts[1].toLowerCase() === "help") {
100
+ this.showSetHelp();
101
+ }
102
+ else if (parts.length >= 3) {
103
+ const key = parts[1];
104
+ const schema = this.sessionVariablesSchema[key];
105
+ if (!schema) {
106
+ logger.always(chalk.red(`Error: Unknown session variable "${key}".`));
107
+ logger.always(chalk.gray('Use "set help" to see available variables.'));
108
+ return true;
109
+ }
110
+ const valueStr = parts.slice(2).join(" ");
111
+ let value = this.parseValue(valueStr);
112
+ // Validate type
113
+ if (schema.type === "boolean" && typeof value !== "boolean") {
114
+ logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a boolean (true/false).`));
115
+ return true;
116
+ }
117
+ if (schema.type === "string") {
118
+ if (typeof value === "number" || typeof value === "boolean") {
119
+ value = String(value);
120
+ }
121
+ else if (typeof value !== "string") {
122
+ logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a string.`));
123
+ return true;
124
+ }
125
+ }
126
+ if (schema.type === "number" && typeof value !== "number") {
127
+ logger.always(chalk.red(`Error: Invalid value for "${key}". Expected a number.`));
128
+ return true;
129
+ }
130
+ // Validate allowedValues
131
+ if (schema.allowedValues &&
132
+ !schema.allowedValues.includes(String(value))) {
133
+ logger.always(chalk.red(`Error: Invalid value for "${key}".`));
134
+ logger.always(chalk.gray(`Allowed values are: ${schema.allowedValues.join(", ")}`));
135
+ return true;
136
+ }
137
+ globalSession.setSessionVariable(key, value);
138
+ logger.always(chalk.green(`✓ ${key} set to ${value}`));
139
+ }
140
+ else {
141
+ logger.always(chalk.red("Usage: set <key> <value> or set help"));
142
+ }
143
+ return true;
144
+ case "get":
145
+ if (parts.length >= 2) {
146
+ const key = parts[1];
147
+ const value = globalSession.getSessionVariable(key);
148
+ if (value !== undefined) {
149
+ logger.always(chalk.cyan(`${key}: ${value}`));
150
+ }
151
+ else {
152
+ logger.always(chalk.yellow(`${key} is not set`));
153
+ }
154
+ }
155
+ else {
156
+ logger.always(chalk.red("Usage: get <key>"));
157
+ }
158
+ return true;
159
+ case "unset":
160
+ if (parts.length >= 2) {
161
+ const key = parts[1];
162
+ if (globalSession.unsetSessionVariable(key)) {
163
+ logger.always(chalk.green(`✓ ${key} unset`));
164
+ }
165
+ else {
166
+ logger.always(chalk.yellow(`${key} was not set`));
167
+ }
168
+ }
169
+ else {
170
+ logger.always(chalk.red("Usage: unset <key>"));
171
+ }
172
+ return true;
173
+ case "show": {
174
+ const variables = globalSession.getSessionVariables();
175
+ if (Object.keys(variables).length > 0) {
176
+ logger.always(chalk.cyan("Session Variables:"));
177
+ for (const [key, value] of Object.entries(variables)) {
178
+ logger.always(chalk.gray(` ${key}: ${value}`));
179
+ }
180
+ }
181
+ else {
182
+ logger.always(chalk.yellow("No session variables set"));
183
+ }
184
+ return true;
185
+ }
186
+ case "clear":
187
+ globalSession.clearSessionVariables();
188
+ logger.always(chalk.green("✓ All session variables cleared"));
189
+ return true;
190
+ default:
191
+ return false;
192
+ }
193
+ }
194
+ parseValue(value) {
195
+ // Try to parse as number
196
+ if (!isNaN(Number(value))) {
197
+ return Number(value);
198
+ }
199
+ // Try to parse as boolean
200
+ if (value.toLowerCase() === "true") {
201
+ return true;
202
+ }
203
+ if (value.toLowerCase() === "false") {
204
+ return false;
205
+ }
206
+ // Return as string
207
+ return value;
208
+ }
209
+ showHelp() {
210
+ logger.always(chalk.cyan("Available Loop Mode Commands:"));
211
+ const commands = [
212
+ {
213
+ cmd: "help",
214
+ desc: "Show this help message.",
215
+ },
216
+ {
217
+ cmd: "set <key> <value>",
218
+ desc: "Set a session variable. Use 'set help' for details.",
219
+ },
220
+ { cmd: "get <key>", desc: "Get a session variable." },
221
+ { cmd: "unset <key>", desc: "Unset a session variable." },
222
+ {
223
+ cmd: "show",
224
+ desc: "Show all currently set session variables.",
225
+ },
226
+ { cmd: "clear", desc: "Clear all session variables." },
227
+ {
228
+ cmd: "exit / quit / :q",
229
+ desc: "Exit the loop mode.",
230
+ },
231
+ ];
232
+ commands.forEach((c) => {
233
+ logger.always(chalk.yellow(` ${c.cmd.padEnd(20)}`) + `${c.desc}`);
234
+ });
235
+ logger.always("\nAny other command will be executed as a standard neurolink CLI command.");
236
+ // Also show the standard help output
237
+ this.initializeCliParser().showHelp("log");
238
+ }
239
+ showSetHelp() {
240
+ logger.always(chalk.cyan("Available Session Variables to Set:"));
241
+ for (const [key, schema] of Object.entries(this.sessionVariablesSchema)) {
242
+ logger.always(chalk.yellow(` ${key}`));
243
+ logger.always(` ${schema.description}`);
244
+ if (schema.allowedValues) {
245
+ logger.always(chalk.gray(` Allowed: ${schema.allowedValues.join(", ")}`));
246
+ }
247
+ else {
248
+ logger.always(chalk.gray(` Type: ${schema.type}`));
249
+ }
250
+ }
251
+ }
252
+ }
@@ -0,0 +1 @@
1
+ export declare function initializeCliParser(): import("yargs").Argv<{}>;
@@ -0,0 +1,161 @@
1
+ import yargs from "yargs";
2
+ import { hideBin } from "yargs/helpers";
3
+ import chalk from "chalk";
4
+ import packageJson from "../../package.json" with { type: "json" };
5
+ import { CLICommandFactory } from "./factories/commandFactory.js";
6
+ import { globalSession } from "../lib/session/globalSessionState.js";
7
+ import { handleError } from "./errorHandler.js";
8
+ import { logger } from "../lib/utils/logger.js";
9
+ import { SetupCommandFactory } from "./factories/setupCommandFactory.js";
10
+ // Enhanced CLI with Professional UX
11
+ export function initializeCliParser() {
12
+ return (yargs(hideBin(process.argv))
13
+ .scriptName("neurolink")
14
+ .usage("Usage: $0 <command> [options]")
15
+ .version(packageJson.version)
16
+ .help()
17
+ .alias("h", "help")
18
+ .alias("V", "version")
19
+ .strictOptions()
20
+ .strictCommands()
21
+ .demandCommand(1, "")
22
+ .recommendCommands()
23
+ .epilogue("For more info: https://github.com/juspay/neurolink")
24
+ .showHelpOnFail(true, "Specify --help for available options")
25
+ .middleware((argv) => {
26
+ // Handle no-color option globally
27
+ if (argv.noColor || process.env.NO_COLOR || !process.stdout.isTTY) {
28
+ process.env.FORCE_COLOR = "0";
29
+ }
30
+ // Handle custom config file
31
+ if (argv.configFile) {
32
+ process.env.NEUROLINK_CONFIG_FILE = argv.configFile;
33
+ }
34
+ // Control SDK logging based on debug flag
35
+ if (argv.debug) {
36
+ process.env.NEUROLINK_DEBUG = "true";
37
+ }
38
+ else {
39
+ // Always set to false when debug is not enabled (including when not provided)
40
+ process.env.NEUROLINK_DEBUG = "false";
41
+ }
42
+ // Keep existing quiet middleware
43
+ if (process.env.NEUROLINK_QUIET === "true" &&
44
+ typeof argv.quiet === "undefined") {
45
+ argv.quiet = true;
46
+ }
47
+ })
48
+ .fail((msg, err, yargsInstance) => {
49
+ // If we are in a loop, we don't want to exit the process.
50
+ // Instead, we just want to display the error and help text.
51
+ if (globalSession.getCurrentSessionId()) {
52
+ if (msg) {
53
+ logger.error(chalk.red(msg)); // This is a yargs validation error (e.g., missing argument)
54
+ yargsInstance.showHelp("log");
55
+ }
56
+ else if (err) {
57
+ // This is an error thrown from a command handler
58
+ // The loop's catch block will handle this, so we just re-throw.
59
+ // throw err;
60
+ handleError(err, "CLI Error in Loop Session");
61
+ }
62
+ return;
63
+ }
64
+ // Original logic for single-command execution
65
+ const exitProcess = () => {
66
+ if (!process.exitCode) {
67
+ process.exit(1);
68
+ }
69
+ };
70
+ if (err) {
71
+ // Error likely from an async command handler (e.g., via _handleError)
72
+ // _handleError already prints and calls process.exit(1).
73
+ // If we're here, it means _handleError's process.exit might not have been caught by the top-level async IIFE.
74
+ // Or, it's a synchronous yargs error during parsing that yargs itself throws.
75
+ const alreadyExitedByHandleError = err?.exitCode !== undefined;
76
+ // A simple heuristic: if the error message doesn't look like one of our handled generic messages,
77
+ // it might be a direct yargs parsing error.
78
+ const isLikelyYargsInternalError = err.message && // Ensure err.message exists
79
+ !err.message.includes("Authentication error") &&
80
+ !err.message.includes("Network error") &&
81
+ !err.message.includes("Authorization error") &&
82
+ !err.message.includes("Permission denied") && // from config export
83
+ !err.message.includes("Invalid or unparseable JSON"); // from config import
84
+ if (!alreadyExitedByHandleError) {
85
+ process.stderr.write(chalk.red(`CLI Error: ${err.message || msg || "An unexpected error occurred."}\n`));
86
+ // If it's a yargs internal parsing error, show help.
87
+ if (isLikelyYargsInternalError && msg) {
88
+ yargsInstance.showHelp((h) => {
89
+ process.stderr.write(h + "\n");
90
+ exitProcess();
91
+ });
92
+ return;
93
+ }
94
+ exitProcess();
95
+ }
96
+ return; // Exit was already called or error handled
97
+ }
98
+ // Yargs parsing/validation error (msg is present, err is null)
99
+ if (msg) {
100
+ let processedMsg = `Error: ${msg}\n`;
101
+ if (msg.includes("Not enough non-option arguments") ||
102
+ msg.includes("Missing required argument") ||
103
+ msg.includes("Unknown command")) {
104
+ process.stderr.write(chalk.red(processedMsg)); // Print error first
105
+ yargsInstance.showHelp((h) => {
106
+ process.stderr.write("\n" + h + "\n");
107
+ exitProcess();
108
+ });
109
+ return; // Exit happens in callback
110
+ }
111
+ else if (msg.includes("Unknown argument") ||
112
+ msg.includes("Invalid values")) {
113
+ processedMsg = `Error: ${msg}\nUse --help to see available options.\n`;
114
+ }
115
+ process.stderr.write(chalk.red(processedMsg));
116
+ }
117
+ else {
118
+ // No specific message, but failure occurred (e.g. demandCommand failed silently)
119
+ yargsInstance.showHelp((h) => {
120
+ process.stderr.write(h + "\n");
121
+ exitProcess();
122
+ });
123
+ return; // Exit happens in callback
124
+ }
125
+ exitProcess(); // Default exit
126
+ })
127
+ // Generate Command (Primary) - Using CLICommandFactory
128
+ .command(CLICommandFactory.createGenerateCommand())
129
+ // Stream Text Command - Using CLICommandFactory
130
+ .command(CLICommandFactory.createStreamCommand())
131
+ // Batch Processing Command - Using CLICommandFactory
132
+ .command(CLICommandFactory.createBatchCommand())
133
+ // Provider Command Group - Using CLICommandFactory
134
+ .command(CLICommandFactory.createProviderCommands())
135
+ // Status command alias - Using CLICommandFactory
136
+ .command(CLICommandFactory.createStatusCommand())
137
+ // Models Command Group - Using CLICommandFactory
138
+ .command(CLICommandFactory.createModelsCommands())
139
+ // MCP Command Group - Using CLICommandFactory
140
+ .command(CLICommandFactory.createMCPCommands())
141
+ // Discover Command - Using CLICommandFactory
142
+ .command(CLICommandFactory.createDiscoverCommand())
143
+ // Configuration Command Group - Using CLICommandFactory
144
+ .command(CLICommandFactory.createConfigCommands())
145
+ // Memory Command Group - Using CLICommandFactory
146
+ .command(CLICommandFactory.createMemoryCommands())
147
+ // Get Best Provider Command - Using CLICommandFactory
148
+ .command(CLICommandFactory.createBestProviderCommand())
149
+ // Validate Command (alias for config validate)
150
+ .command(CLICommandFactory.createValidateCommand())
151
+ // Completion Command - Using CLICommandFactory
152
+ .command(CLICommandFactory.createCompletionCommand())
153
+ // Ollama Command Group - Using CLICommandFactory
154
+ .command(CLICommandFactory.createOllamaCommands())
155
+ // SageMaker Command Group - Using CLICommandFactory
156
+ .command(CLICommandFactory.createSageMakerCommands())
157
+ // Loop Command - Using CLICommandFactory
158
+ .command(CLICommandFactory.createLoopCommand())
159
+ // Setup Commands - Using SetupCommandFactory
160
+ .command(SetupCommandFactory.createSetupCommands())); // Close the main return statement
161
+ }
@@ -12,6 +12,7 @@ export interface EnvUpdateResult {
12
12
  updated: string[];
13
13
  added: string[];
14
14
  unchanged: string[];
15
+ deleted: string[];
15
16
  }
16
17
  /**
17
18
  * Create a timestamped backup of the existing .env file
@@ -24,11 +25,11 @@ export declare function parseEnvFile(content: string): Record<string, string>;
24
25
  /**
25
26
  * Generate .env file content from key-value pairs
26
27
  */
27
- export declare function generateEnvContent(envVars: Record<string, string>, existingContent?: string): string;
28
+ export declare function generateEnvContent(envVars: Record<string, string>, existingContent?: string, keysToDelete?: string[]): string;
28
29
  /**
29
30
  * Update .env file with new environment variables
30
31
  */
31
- export declare function updateEnvFile(newVars: Record<string, string>, envPath?: string, createBackup?: boolean): EnvUpdateResult;
32
+ export declare function updateEnvFile(newVars: Record<string, string>, envPath?: string, createBackup?: boolean, keysToDelete?: string[]): EnvUpdateResult;
32
33
  /**
33
34
  * Display environment file update summary
34
35
  */
@@ -59,7 +59,7 @@ export function parseEnvFile(content) {
59
59
  /**
60
60
  * Generate .env file content from key-value pairs
61
61
  */
62
- export function generateEnvContent(envVars, existingContent) {
62
+ export function generateEnvContent(envVars, existingContent, keysToDelete = []) {
63
63
  const lines = [];
64
64
  const _existingVars = existingContent ? parseEnvFile(existingContent) : {};
65
65
  const processedKeys = new Set();
@@ -79,6 +79,10 @@ export function generateEnvContent(envVars, existingContent) {
79
79
  continue;
80
80
  }
81
81
  const key = trimmedLine.substring(0, equalIndex).trim();
82
+ // Skip keys that should be deleted
83
+ if (keysToDelete.includes(key)) {
84
+ continue; // Skip this line - delete the key
85
+ }
82
86
  if (Object.prototype.hasOwnProperty.call(envVars, key)) {
83
87
  // Update existing variable
84
88
  lines.push(`${key}=${envVars[key]}`);
@@ -108,12 +112,13 @@ export function generateEnvContent(envVars, existingContent) {
108
112
  /**
109
113
  * Update .env file with new environment variables
110
114
  */
111
- export function updateEnvFile(newVars, envPath = ".env", createBackup = true) {
115
+ export function updateEnvFile(newVars, envPath = ".env", createBackup = true, keysToDelete = []) {
112
116
  const result = {
113
117
  backup: { existed: false },
114
118
  updated: [],
115
119
  added: [],
116
120
  unchanged: [],
121
+ deleted: [],
117
122
  };
118
123
  // Create backup if requested and file exists
119
124
  if (createBackup) {
@@ -126,6 +131,12 @@ export function updateEnvFile(newVars, envPath = ".env", createBackup = true) {
126
131
  existingContent = fs.readFileSync(envPath, "utf8");
127
132
  _existingVars = parseEnvFile(existingContent);
128
133
  }
134
+ // Track keys to be deleted
135
+ for (const key of keysToDelete) {
136
+ if (Object.prototype.hasOwnProperty.call(_existingVars, key)) {
137
+ result.deleted.push(key);
138
+ }
139
+ }
129
140
  // Categorize changes
130
141
  for (const [key, value] of Object.entries(newVars)) {
131
142
  if (Object.prototype.hasOwnProperty.call(_existingVars, key)) {
@@ -141,7 +152,7 @@ export function updateEnvFile(newVars, envPath = ".env", createBackup = true) {
141
152
  }
142
153
  }
143
154
  // Generate new content
144
- const newContent = generateEnvContent(newVars, existingContent);
155
+ const newContent = generateEnvContent(newVars, existingContent, keysToDelete);
145
156
  // Write updated file
146
157
  try {
147
158
  fs.writeFileSync(envPath, newContent, "utf8");
@@ -167,10 +178,13 @@ export function displayEnvUpdateSummary(result, quiet = false) {
167
178
  if (result.updated.length > 0) {
168
179
  logger.always(chalk.yellow(`🔄 Updated ${result.updated.length} existing variables: ${result.updated.join(", ")}`));
169
180
  }
181
+ if (result.deleted.length > 0) {
182
+ logger.always(chalk.red(`🗑️ Deleted ${result.deleted.length} variables: ${result.deleted.join(", ")}`));
183
+ }
170
184
  if (result.unchanged.length > 0) {
171
185
  logger.always(chalk.gray(`✓ ${result.unchanged.length} variables unchanged: ${result.unchanged.join(", ")}`));
172
186
  }
173
- const totalChanges = result.added.length + result.updated.length;
187
+ const totalChanges = result.added.length + result.updated.length + result.deleted.length;
174
188
  if (totalChanges > 0) {
175
189
  logger.always(chalk.blue(`📝 Environment file updated with ${totalChanges} changes`));
176
190
  }
@@ -126,6 +126,9 @@ export class OllamaUtils {
126
126
  stdio: "ignore",
127
127
  detached: true,
128
128
  });
129
+ child.on("error", (err) => {
130
+ logger.error("Error starting Ollama serve process:", err);
131
+ });
129
132
  child.unref();
130
133
  logger.always(chalk.green("✅ Ollama service started"));
131
134
  }
@@ -141,6 +144,9 @@ export class OllamaUtils {
141
144
  stdio: "ignore",
142
145
  detached: true,
143
146
  });
147
+ child.on("error", (err) => {
148
+ logger.error("Error starting Ollama serve process:", err);
149
+ });
144
150
  child.unref();
145
151
  logger.always(chalk.green("✅ Ollama service started"));
146
152
  }
@@ -2,7 +2,7 @@
2
2
  * Conversation Memory Configuration
3
3
  * Provides default values for conversation memory feature with environment variable support
4
4
  */
5
- import type { ConversationMemoryConfig } from "../types/conversationTypes.js";
5
+ import type { ConversationMemoryConfig } from "../types/conversation.js";
6
6
  /**
7
7
  * Default maximum number of turns per session
8
8
  */
@@ -100,7 +100,15 @@ export class BaseProvider {
100
100
  yield { content: buffer };
101
101
  buffer = "";
102
102
  // Small delay to simulate streaming (1-10ms)
103
- await new Promise((resolve) => setTimeout(resolve, Math.random() * 9 + 1));
103
+ await new Promise((resolve, reject) => {
104
+ const timeoutId = setTimeout(resolve, Math.random() * 9 + 1);
105
+ // Handle potential timeout issues
106
+ if (!timeoutId) {
107
+ reject(new Error("Failed to create timeout"));
108
+ }
109
+ }).catch((err) => {
110
+ logger.error("Error in streaming delay:", err);
111
+ });
104
112
  }
105
113
  }
106
114
  // Yield all remaining content
@@ -217,8 +225,14 @@ export class BaseProvider {
217
225
  // Accumulate the streamed content
218
226
  let accumulatedContent = "";
219
227
  // Wait for the stream to complete and accumulate content
220
- for await (const chunk of streamResult.textStream) {
221
- accumulatedContent += chunk;
228
+ try {
229
+ for await (const chunk of streamResult.textStream) {
230
+ accumulatedContent += chunk;
231
+ }
232
+ }
233
+ catch (streamError) {
234
+ logger.error(`Error reading text stream for ${this.providerName}:`, streamError);
235
+ throw streamError;
222
236
  }
223
237
  // Get the final result - this should include usage, toolCalls, etc.
224
238
  const usage = await streamResult.usage;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Conversation Memory Factory for NeuroLink
3
+ * Creates appropriate conversation memory manager based on configuration
4
+ */
5
+ import type { ConversationMemoryConfig, RedisStorageConfig } from "../types/conversation.js";
6
+ import { ConversationMemoryManager } from "./conversationMemoryManager.js";
7
+ import { RedisConversationMemoryManager } from "./redisConversationMemoryManager.js";
8
+ /**
9
+ * Configuration for memory storage type
10
+ */
11
+ export type StorageType = "memory" | "redis";
12
+ /**
13
+ * Creates a conversation memory manager based on configuration
14
+ */
15
+ export declare function createConversationMemoryManager(config: ConversationMemoryConfig, storageType?: StorageType, redisConfig?: RedisStorageConfig): ConversationMemoryManager | RedisConversationMemoryManager;
16
+ /**
17
+ * Get storage type from environment variable or configuration
18
+ */
19
+ export declare function getStorageType(): StorageType;
20
+ /**
21
+ * Get Redis configuration from environment variables
22
+ */
23
+ export declare function getRedisConfigFromEnv(): RedisStorageConfig;