@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.
- package/CHANGELOG.md +15 -0
- package/README.md +101 -7
- package/dist/cli/commands/setup-anthropic.d.ts +16 -0
- package/dist/cli/commands/setup-anthropic.js +414 -0
- package/dist/cli/commands/setup-azure.d.ts +17 -0
- package/dist/cli/commands/setup-azure.js +415 -0
- package/dist/cli/commands/setup-bedrock.d.ts +13 -0
- package/dist/cli/commands/setup-bedrock.js +487 -0
- package/dist/cli/commands/setup-gcp.d.ts +18 -0
- package/dist/cli/commands/setup-gcp.js +569 -0
- package/dist/cli/commands/setup-google-ai.d.ts +16 -0
- package/dist/cli/commands/setup-google-ai.js +369 -0
- package/dist/cli/commands/setup-huggingface.d.ts +8 -0
- package/dist/cli/commands/setup-huggingface.js +200 -0
- package/dist/cli/commands/setup-mistral.d.ts +8 -0
- package/dist/cli/commands/setup-mistral.js +233 -0
- package/dist/cli/commands/setup-openai.d.ts +16 -0
- package/dist/cli/commands/setup-openai.js +402 -0
- package/dist/cli/commands/setup.d.ts +19 -0
- package/dist/cli/commands/setup.js +539 -0
- package/dist/cli/errorHandler.d.ts +1 -0
- package/dist/cli/errorHandler.js +28 -0
- package/dist/cli/factories/commandFactory.d.ts +27 -0
- package/dist/cli/factories/commandFactory.js +416 -60
- package/dist/cli/factories/ollamaCommandFactory.js +7 -1
- package/dist/cli/factories/setupCommandFactory.d.ts +18 -0
- package/dist/cli/factories/setupCommandFactory.js +137 -0
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +9 -164
- package/dist/cli/loop/optionsSchema.d.ts +15 -0
- package/dist/cli/loop/optionsSchema.js +59 -0
- package/dist/cli/loop/session.d.ts +15 -0
- package/dist/cli/loop/session.js +252 -0
- package/dist/cli/parser.d.ts +1 -0
- package/dist/cli/parser.js +161 -0
- package/dist/cli/utils/envManager.d.ts +3 -2
- package/dist/cli/utils/envManager.js +18 -4
- package/dist/cli/utils/ollamaUtils.js +6 -0
- package/dist/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
- package/dist/core/baseProvider.js +17 -3
- package/dist/core/conversationMemoryFactory.d.ts +23 -0
- package/dist/core/conversationMemoryFactory.js +144 -0
- package/dist/core/conversationMemoryInitializer.d.ts +14 -0
- package/dist/core/conversationMemoryInitializer.js +127 -0
- package/dist/core/conversationMemoryManager.d.ts +3 -2
- package/dist/core/conversationMemoryManager.js +4 -3
- package/dist/core/redisConversationMemoryManager.d.ts +73 -0
- package/dist/core/redisConversationMemoryManager.js +483 -0
- package/dist/core/types.d.ts +1 -1
- package/dist/lib/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
- package/dist/lib/core/baseProvider.js +17 -3
- package/dist/lib/core/conversationMemoryFactory.d.ts +23 -0
- package/dist/lib/core/conversationMemoryFactory.js +144 -0
- package/dist/lib/core/conversationMemoryInitializer.d.ts +14 -0
- package/dist/lib/core/conversationMemoryInitializer.js +127 -0
- package/dist/lib/core/conversationMemoryManager.d.ts +3 -2
- package/dist/lib/core/conversationMemoryManager.js +4 -3
- package/dist/lib/core/redisConversationMemoryManager.d.ts +73 -0
- package/dist/lib/core/redisConversationMemoryManager.js +483 -0
- package/dist/lib/core/types.d.ts +1 -1
- package/dist/lib/neurolink.d.ts +15 -9
- package/dist/lib/neurolink.js +218 -67
- package/dist/lib/providers/amazonBedrock.d.ts +4 -4
- package/dist/lib/providers/anthropic.d.ts +4 -4
- package/dist/lib/providers/azureOpenai.d.ts +4 -4
- package/dist/lib/providers/googleAiStudio.d.ts +4 -4
- package/dist/lib/providers/googleAiStudio.js +1 -1
- package/dist/lib/providers/huggingFace.d.ts +4 -4
- package/dist/lib/providers/litellm.d.ts +1 -1
- package/dist/lib/providers/mistral.d.ts +4 -4
- package/dist/lib/providers/mistral.js +2 -2
- package/dist/lib/providers/openAI.d.ts +4 -4
- package/dist/lib/session/globalSessionState.d.ts +27 -0
- package/dist/lib/session/globalSessionState.js +77 -0
- package/dist/lib/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
- package/dist/lib/types/generateTypes.d.ts +1 -1
- package/dist/lib/types/streamTypes.d.ts +1 -1
- package/dist/lib/utils/conversationMemory.d.ts +22 -0
- package/dist/lib/utils/conversationMemory.js +121 -0
- package/dist/lib/utils/conversationMemoryUtils.d.ts +1 -1
- package/dist/lib/utils/conversationMemoryUtils.js +2 -2
- package/dist/lib/utils/messageBuilder.d.ts +1 -1
- package/dist/lib/utils/messageBuilder.js +1 -1
- package/dist/lib/utils/redis.d.ts +42 -0
- package/dist/lib/utils/redis.js +263 -0
- package/dist/neurolink.d.ts +15 -9
- package/dist/neurolink.js +218 -67
- package/dist/providers/amazonBedrock.d.ts +4 -4
- package/dist/providers/anthropic.d.ts +4 -4
- package/dist/providers/azureOpenai.d.ts +4 -4
- package/dist/providers/googleAiStudio.d.ts +4 -4
- package/dist/providers/googleAiStudio.js +1 -1
- package/dist/providers/huggingFace.d.ts +4 -4
- package/dist/providers/litellm.d.ts +1 -1
- package/dist/providers/mistral.d.ts +4 -4
- package/dist/providers/mistral.js +2 -2
- package/dist/providers/openAI.d.ts +4 -4
- package/dist/session/globalSessionState.d.ts +27 -0
- package/dist/session/globalSessionState.js +77 -0
- package/dist/types/{conversationTypes.d.ts → conversation.d.ts} +32 -0
- package/dist/types/generateTypes.d.ts +1 -1
- package/dist/types/streamTypes.d.ts +1 -1
- package/dist/utils/conversationMemory.d.ts +22 -0
- package/dist/utils/conversationMemory.js +121 -0
- package/dist/utils/conversationMemoryUtils.d.ts +1 -1
- package/dist/utils/conversationMemoryUtils.js +2 -2
- package/dist/utils/messageBuilder.d.ts +1 -1
- package/dist/utils/messageBuilder.js +1 -1
- package/dist/utils/redis.d.ts +42 -0
- package/dist/utils/redis.js +263 -0
- package/package.json +3 -1
- /package/dist/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
- /package/dist/lib/config/{conversationMemoryConfig.js → conversationMemory.js} +0 -0
- /package/dist/lib/types/{conversationTypes.js → conversation.js} +0 -0
- /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/
|
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
|
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
|
-
|
221
|
-
|
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;
|