@juspay/neurolink 7.33.3 → 7.34.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 +37 -0
- package/dist/cli/commands/config.d.ts +3 -4
- package/dist/cli/commands/config.js +2 -3
- package/dist/cli/errorHandler.d.ts +1 -0
- package/dist/cli/errorHandler.js +28 -0
- package/dist/cli/factories/commandFactory.d.ts +23 -0
- package/dist/cli/factories/commandFactory.js +375 -60
- package/dist/cli/factories/ollamaCommandFactory.js +7 -1
- 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 +158 -0
- package/dist/cli/utils/ollamaUtils.js +6 -0
- package/dist/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
- package/dist/core/baseProvider.js +43 -4
- package/dist/core/constants.d.ts +12 -3
- package/dist/core/constants.js +22 -6
- 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/factory.js +19 -0
- 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/factories/providerRegistry.js +2 -0
- package/dist/lib/config/{conversationMemoryConfig.d.ts → conversationMemory.d.ts} +1 -1
- package/dist/lib/core/baseProvider.js +43 -4
- package/dist/lib/core/constants.d.ts +12 -3
- package/dist/lib/core/constants.js +22 -6
- 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/factory.js +19 -0
- 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/factories/providerRegistry.js +2 -0
- package/dist/lib/mcp/servers/aiProviders/aiWorkflowTools.js +2 -2
- 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/amazonBedrock.js +2 -2
- package/dist/lib/providers/anthropic.d.ts +4 -4
- package/dist/lib/providers/anthropic.js +3 -12
- package/dist/lib/providers/anthropicBaseProvider.js +1 -2
- package/dist/lib/providers/azureOpenai.d.ts +4 -4
- package/dist/lib/providers/azureOpenai.js +49 -8
- package/dist/lib/providers/googleAiStudio.d.ts +4 -4
- package/dist/lib/providers/googleAiStudio.js +2 -2
- package/dist/lib/providers/googleVertex.js +2 -2
- package/dist/lib/providers/huggingFace.d.ts +4 -4
- package/dist/lib/providers/huggingFace.js +1 -2
- package/dist/lib/providers/litellm.d.ts +1 -1
- package/dist/lib/providers/litellm.js +1 -2
- package/dist/lib/providers/mistral.d.ts +4 -4
- package/dist/lib/providers/mistral.js +4 -4
- package/dist/lib/providers/ollama.js +7 -8
- package/dist/lib/providers/openAI.d.ts +4 -4
- package/dist/lib/providers/openAI.js +2 -2
- package/dist/lib/providers/openaiCompatible.js +5 -2
- package/dist/lib/providers/sagemaker/language-model.d.ts +5 -0
- package/dist/lib/providers/sagemaker/language-model.js +9 -1
- 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/providerHealth.js +7 -3
- package/dist/lib/utils/redis.d.ts +42 -0
- package/dist/lib/utils/redis.js +263 -0
- package/dist/lib/utils/tokenLimits.d.ts +2 -2
- package/dist/lib/utils/tokenLimits.js +10 -3
- package/dist/mcp/servers/aiProviders/aiWorkflowTools.js +2 -2
- package/dist/neurolink.d.ts +15 -9
- package/dist/neurolink.js +218 -67
- package/dist/providers/amazonBedrock.d.ts +4 -4
- package/dist/providers/amazonBedrock.js +2 -2
- package/dist/providers/anthropic.d.ts +4 -4
- package/dist/providers/anthropic.js +3 -12
- package/dist/providers/anthropicBaseProvider.js +1 -2
- package/dist/providers/azureOpenai.d.ts +4 -4
- package/dist/providers/azureOpenai.js +49 -8
- package/dist/providers/googleAiStudio.d.ts +4 -4
- package/dist/providers/googleAiStudio.js +2 -2
- package/dist/providers/googleVertex.js +2 -2
- package/dist/providers/huggingFace.d.ts +4 -4
- package/dist/providers/huggingFace.js +1 -2
- package/dist/providers/litellm.d.ts +1 -1
- package/dist/providers/litellm.js +1 -2
- package/dist/providers/mistral.d.ts +4 -4
- package/dist/providers/mistral.js +4 -4
- package/dist/providers/ollama.js +7 -8
- package/dist/providers/openAI.d.ts +4 -4
- package/dist/providers/openAI.js +2 -2
- package/dist/providers/openaiCompatible.js +5 -2
- package/dist/providers/sagemaker/language-model.d.ts +5 -0
- package/dist/providers/sagemaker/language-model.js +9 -1
- 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/providerHealth.js +7 -3
- package/dist/utils/redis.d.ts +42 -0
- package/dist/utils/redis.js +263 -0
- package/dist/utils/tokenLimits.d.ts +2 -2
- package/dist/utils/tokenLimits.js +10 -3
- 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
package/dist/cli/index.js
CHANGED
@@ -5,15 +5,8 @@
|
|
5
5
|
* Professional CLI experience with minimal maintenance overhead.
|
6
6
|
* Features: Spinners, colors, batch processing, provider testing, rich help
|
7
7
|
*/
|
8
|
-
import
|
9
|
-
import { hideBin } from "yargs/helpers";
|
8
|
+
import { initializeCliParser } from "./parser.js";
|
10
9
|
import chalk from "chalk";
|
11
|
-
import _fs from "fs";
|
12
|
-
import path from "path";
|
13
|
-
import { fileURLToPath } from "url";
|
14
|
-
import { CLICommandFactory } from "./factories/commandFactory.js";
|
15
|
-
import { AuthenticationError, AuthorizationError, NetworkError, RateLimitError, } from "../lib/types/errors.js";
|
16
|
-
import { logger } from "../lib/utils/logger.js";
|
17
10
|
// Clean up pnpm-specific environment variables that cause npm warnings
|
18
11
|
// These variables are set by pnpm but cause "Unknown env config" warnings in npm
|
19
12
|
if (process.env.npm_config_verify_deps_before_run) {
|
@@ -22,11 +15,6 @@ if (process.env.npm_config_verify_deps_before_run) {
|
|
22
15
|
if (process.env.npm_config__jsr_registry) {
|
23
16
|
delete process.env.npm_config__jsr_registry;
|
24
17
|
}
|
25
|
-
// Get version from package.json
|
26
|
-
const __filename = fileURLToPath(import.meta.url);
|
27
|
-
const __dirname = path.dirname(__filename);
|
28
|
-
const packageJson = JSON.parse(_fs.readFileSync(path.resolve(__dirname, "../../package.json"), "utf-8"));
|
29
|
-
const cliVersion = packageJson.version;
|
30
18
|
// Load environment variables from .env file
|
31
19
|
try {
|
32
20
|
// Try to import and configure dotenv
|
@@ -37,158 +25,8 @@ catch {
|
|
37
25
|
// dotenv is not available (dev dependency only) - this is fine for production
|
38
26
|
// Environment variables should be set externally in production
|
39
27
|
}
|
40
|
-
// Utility Functions (Simple, Zero Maintenance)
|
41
|
-
export function handleError(_error, context) {
|
42
|
-
logger.error(chalk.red(`❌ ${context} failed: ${_error.message}`));
|
43
|
-
if (_error instanceof AuthenticationError) {
|
44
|
-
logger.error(chalk.yellow("💡 Set Google AI Studio API key (RECOMMENDED): export GOOGLE_AI_API_KEY=AIza-..."));
|
45
|
-
logger.error(chalk.yellow("💡 Or set OpenAI API key: export OPENAI_API_KEY=sk-..."));
|
46
|
-
logger.error(chalk.yellow("💡 Or set AWS Bedrock credentials: export AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... AWS_REGION=us-east-1"));
|
47
|
-
logger.error(chalk.yellow("💡 Or set Google Vertex AI credentials: export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json"));
|
48
|
-
logger.error(chalk.yellow("💡 Or set Anthropic API key: export ANTHROPIC_API_KEY=sk-ant-..."));
|
49
|
-
logger.error(chalk.yellow("💡 Or set Azure OpenAI credentials: export AZURE_OPENAI_API_KEY=... AZURE_OPENAI_ENDPOINT=..."));
|
50
|
-
}
|
51
|
-
else if (_error instanceof RateLimitError) {
|
52
|
-
logger.error(chalk.yellow("💡 Try again in a few moments or use --provider vertex"));
|
53
|
-
}
|
54
|
-
else if (_error instanceof AuthorizationError) {
|
55
|
-
logger.error(chalk.yellow("💡 Check your account permissions for the selected model/service."));
|
56
|
-
logger.error(chalk.yellow("💡 For AWS Bedrock, ensure you have permissions for the specific model and consider using inference profile ARNs."));
|
57
|
-
}
|
58
|
-
else if (_error instanceof NetworkError) {
|
59
|
-
logger.error(chalk.yellow("💡 Check your internet connection and the provider's status page."));
|
60
|
-
}
|
61
|
-
process.exit(1);
|
62
|
-
}
|
63
|
-
// Manual pre-validation for unknown flags
|
64
|
-
const args = hideBin(process.argv);
|
65
28
|
// Enhanced CLI with Professional UX
|
66
|
-
const cli =
|
67
|
-
.scriptName("neurolink")
|
68
|
-
.usage("Usage: $0 <command> [options]")
|
69
|
-
.version(cliVersion)
|
70
|
-
.help()
|
71
|
-
.alias("h", "help")
|
72
|
-
.alias("V", "version")
|
73
|
-
.strictOptions()
|
74
|
-
.strictCommands()
|
75
|
-
.demandCommand(1, "")
|
76
|
-
.epilogue("For more info: https://github.com/juspay/neurolink")
|
77
|
-
.showHelpOnFail(true, "Specify --help for available options")
|
78
|
-
.middleware((argv) => {
|
79
|
-
// Handle no-color option globally
|
80
|
-
if (argv.noColor || process.env.NO_COLOR || !process.stdout.isTTY) {
|
81
|
-
process.env.FORCE_COLOR = "0";
|
82
|
-
}
|
83
|
-
// Handle custom config file
|
84
|
-
if (argv.configFile) {
|
85
|
-
process.env.NEUROLINK_CONFIG_FILE = argv.configFile;
|
86
|
-
}
|
87
|
-
// Control SDK logging based on debug flag
|
88
|
-
if (argv.debug) {
|
89
|
-
process.env.NEUROLINK_DEBUG = "true";
|
90
|
-
}
|
91
|
-
else {
|
92
|
-
// Always set to false when debug is not enabled (including when not provided)
|
93
|
-
process.env.NEUROLINK_DEBUG = "false";
|
94
|
-
}
|
95
|
-
// Keep existing quiet middleware
|
96
|
-
if (process.env.NEUROLINK_QUIET === "true" &&
|
97
|
-
typeof argv.quiet === "undefined") {
|
98
|
-
argv.quiet = true;
|
99
|
-
}
|
100
|
-
})
|
101
|
-
.fail((msg, err, yargsInstance) => {
|
102
|
-
const exitProcess = () => {
|
103
|
-
if (!process.exitCode) {
|
104
|
-
process.exit(1);
|
105
|
-
}
|
106
|
-
};
|
107
|
-
if (err) {
|
108
|
-
// Error likely from an async command handler (e.g., via _handleError)
|
109
|
-
// _handleError already prints and calls process.exit(1).
|
110
|
-
// If we're here, it means _handleError's process.exit might not have been caught by the top-level async IIFE.
|
111
|
-
// Or, it's a synchronous yargs error during parsing that yargs itself throws.
|
112
|
-
const alreadyExitedByHandleError = err?.exitCode !== undefined;
|
113
|
-
// A simple heuristic: if the error message doesn't look like one of our handled generic messages,
|
114
|
-
// it might be a direct yargs parsing error.
|
115
|
-
const isLikelyYargsInternalError = err.message && // Ensure err.message exists
|
116
|
-
!err.message.includes("Authentication error") &&
|
117
|
-
!err.message.includes("Network error") &&
|
118
|
-
!err.message.includes("Authorization error") &&
|
119
|
-
!err.message.includes("Permission denied") && // from config export
|
120
|
-
!err.message.includes("Invalid or unparseable JSON"); // from config import
|
121
|
-
if (!alreadyExitedByHandleError) {
|
122
|
-
process.stderr.write(chalk.red(`CLI Error: ${err.message || msg || "An unexpected error occurred."}\n`));
|
123
|
-
// If it's a yargs internal parsing error, show help.
|
124
|
-
if (isLikelyYargsInternalError && msg) {
|
125
|
-
yargsInstance.showHelp((h) => {
|
126
|
-
process.stderr.write(h + "\n");
|
127
|
-
exitProcess();
|
128
|
-
});
|
129
|
-
return;
|
130
|
-
}
|
131
|
-
exitProcess();
|
132
|
-
}
|
133
|
-
return; // Exit was already called or error handled
|
134
|
-
}
|
135
|
-
// Yargs parsing/validation error (msg is present, err is null)
|
136
|
-
if (msg) {
|
137
|
-
let processedMsg = `Error: ${msg}\n`;
|
138
|
-
if (msg.includes("Not enough non-option arguments") ||
|
139
|
-
msg.includes("Missing required argument") ||
|
140
|
-
msg.includes("Unknown command")) {
|
141
|
-
process.stderr.write(chalk.red(processedMsg)); // Print error first
|
142
|
-
yargsInstance.showHelp((h) => {
|
143
|
-
process.stderr.write("\n" + h + "\n");
|
144
|
-
exitProcess();
|
145
|
-
});
|
146
|
-
return; // Exit happens in callback
|
147
|
-
}
|
148
|
-
else if (msg.includes("Unknown argument") ||
|
149
|
-
msg.includes("Invalid values")) {
|
150
|
-
processedMsg = `Error: ${msg}\nUse --help to see available options.\n`;
|
151
|
-
}
|
152
|
-
process.stderr.write(chalk.red(processedMsg));
|
153
|
-
}
|
154
|
-
else {
|
155
|
-
// No specific message, but failure occurred (e.g. demandCommand failed silently)
|
156
|
-
yargsInstance.showHelp((h) => {
|
157
|
-
process.stderr.write(h + "\n");
|
158
|
-
exitProcess();
|
159
|
-
});
|
160
|
-
return; // Exit happens in callback
|
161
|
-
}
|
162
|
-
exitProcess(); // Default exit
|
163
|
-
})
|
164
|
-
// Generate Command (Primary) - Using CLICommandFactory
|
165
|
-
.command(CLICommandFactory.createGenerateCommand())
|
166
|
-
// Stream Text Command - Using CLICommandFactory
|
167
|
-
.command(CLICommandFactory.createStreamCommand())
|
168
|
-
// Batch Processing Command - Using CLICommandFactory
|
169
|
-
.command(CLICommandFactory.createBatchCommand())
|
170
|
-
// Provider Command Group - Using CLICommandFactory
|
171
|
-
.command(CLICommandFactory.createProviderCommands())
|
172
|
-
// Status command alias - Using CLICommandFactory
|
173
|
-
.command(CLICommandFactory.createStatusCommand())
|
174
|
-
// Models Command Group - Using CLICommandFactory
|
175
|
-
.command(CLICommandFactory.createModelsCommands())
|
176
|
-
// MCP Command Group - Using CLICommandFactory
|
177
|
-
.command(CLICommandFactory.createMCPCommands())
|
178
|
-
// Discover Command - Using CLICommandFactory
|
179
|
-
.command(CLICommandFactory.createDiscoverCommand())
|
180
|
-
// Configuration Command Group - Using CLICommandFactory
|
181
|
-
.command(CLICommandFactory.createConfigCommands())
|
182
|
-
// Get Best Provider Command - Using CLICommandFactory
|
183
|
-
.command(CLICommandFactory.createBestProviderCommand())
|
184
|
-
// Validate Command (alias for config validate)
|
185
|
-
.command(CLICommandFactory.createValidateCommand())
|
186
|
-
// Completion Command - Using CLICommandFactory
|
187
|
-
.command(CLICommandFactory.createCompletionCommand())
|
188
|
-
// Ollama Command Group - Using CLICommandFactory
|
189
|
-
.command(CLICommandFactory.createOllamaCommands())
|
190
|
-
// SageMaker Command Group - Using CLICommandFactory
|
191
|
-
.command(CLICommandFactory.createSageMakerCommands());
|
29
|
+
const cli = initializeCliParser();
|
192
30
|
// Execute CLI
|
193
31
|
(async () => {
|
194
32
|
try {
|
@@ -201,3 +39,10 @@ const cli = yargs(args)
|
|
201
39
|
process.exit(1);
|
202
40
|
}
|
203
41
|
})();
|
42
|
+
// Cleanup on exit
|
43
|
+
process.on("SIGINT", () => {
|
44
|
+
process.exit(0);
|
45
|
+
});
|
46
|
+
process.on("SIGTERM", () => {
|
47
|
+
process.exit(0);
|
48
|
+
});
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { type TextGenerationOptions } from "../../lib/core/types.js";
|
2
|
+
/**
|
3
|
+
* Defines the schema for a session variable or a generation option.
|
4
|
+
*/
|
5
|
+
export interface OptionSchema {
|
6
|
+
type: "string" | "boolean" | "number";
|
7
|
+
description: string;
|
8
|
+
allowedValues?: string[];
|
9
|
+
}
|
10
|
+
/**
|
11
|
+
* Master schema for all text generation options.
|
12
|
+
* This object provides metadata for validation and help text in the CLI loop.
|
13
|
+
* It is derived from the main TextGenerationOptions interface to ensure consistency.
|
14
|
+
*/
|
15
|
+
export declare const textGenerationOptionsSchema: Record<keyof Omit<TextGenerationOptions, "prompt" | "input" | "schema" | "tools" | "context" | "conversationHistory" | "conversationMessages" | "conversationMemoryConfig" | "originalPrompt" | "middleware" | "expectedOutcome" | "evaluationCriteria">, OptionSchema>;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import { AIProviderName, } from "../../lib/core/types.js";
|
2
|
+
/**
|
3
|
+
* Master schema for all text generation options.
|
4
|
+
* This object provides metadata for validation and help text in the CLI loop.
|
5
|
+
* It is derived from the main TextGenerationOptions interface to ensure consistency.
|
6
|
+
*/
|
7
|
+
export const textGenerationOptionsSchema = {
|
8
|
+
provider: {
|
9
|
+
type: "string",
|
10
|
+
description: "The AI provider to use.",
|
11
|
+
allowedValues: Object.values(AIProviderName)
|
12
|
+
.filter((p) => typeof p === "string")
|
13
|
+
.filter((p) => p !== AIProviderName.AUTO),
|
14
|
+
},
|
15
|
+
model: {
|
16
|
+
type: "string",
|
17
|
+
description: "The specific model to use from the provider.",
|
18
|
+
},
|
19
|
+
temperature: {
|
20
|
+
type: "number",
|
21
|
+
description: "Controls randomness of the output (e.g., 0.2, 0.8).",
|
22
|
+
},
|
23
|
+
maxTokens: {
|
24
|
+
type: "number",
|
25
|
+
description: "The maximum number of tokens to generate.",
|
26
|
+
},
|
27
|
+
systemPrompt: {
|
28
|
+
type: "string",
|
29
|
+
description: "The system prompt to guide the AI's behavior.",
|
30
|
+
},
|
31
|
+
timeout: {
|
32
|
+
type: "number",
|
33
|
+
description: "Timeout for the generation request in milliseconds.",
|
34
|
+
},
|
35
|
+
disableTools: {
|
36
|
+
type: "boolean",
|
37
|
+
description: "Disable all tool usage for the AI.",
|
38
|
+
},
|
39
|
+
maxSteps: {
|
40
|
+
type: "number",
|
41
|
+
description: "Maximum number of tool execution steps.",
|
42
|
+
},
|
43
|
+
enableAnalytics: {
|
44
|
+
type: "boolean",
|
45
|
+
description: "Enable or disable analytics for responses.",
|
46
|
+
},
|
47
|
+
enableEvaluation: {
|
48
|
+
type: "boolean",
|
49
|
+
description: "Enable or disable AI-powered evaluation of responses.",
|
50
|
+
},
|
51
|
+
evaluationDomain: {
|
52
|
+
type: "string",
|
53
|
+
description: 'Domain expertise for evaluation (e.g., "general AI assistant").',
|
54
|
+
},
|
55
|
+
toolUsageContext: {
|
56
|
+
type: "string",
|
57
|
+
description: "Context about tools/MCPs used in the interaction.",
|
58
|
+
},
|
59
|
+
};
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import type { Argv } from "yargs";
|
2
|
+
import type { ConversationMemoryConfig } from "../../lib/types/conversation.js";
|
3
|
+
export declare class LoopSession {
|
4
|
+
private conversationMemoryConfig?;
|
5
|
+
private initializeCliParser;
|
6
|
+
private isRunning;
|
7
|
+
private sessionId?;
|
8
|
+
private sessionVariablesSchema;
|
9
|
+
constructor(initializeCliParser: () => Argv, conversationMemoryConfig?: ConversationMemoryConfig | undefined);
|
10
|
+
start(): Promise<void>;
|
11
|
+
private handleSessionCommands;
|
12
|
+
private parseValue;
|
13
|
+
private showHelp;
|
14
|
+
private showSetHelp;
|
15
|
+
}
|
@@ -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<{}>;
|