4runr-os 1.0.9 → 1.0.12
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/dist/auth.d.ts +56 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +133 -0
- package/dist/auth.js.map +1 -0
- package/dist/index.js +476 -74
- package/dist/index.js.map +1 -1
- package/dist/local-model-executor.d.ts +41 -0
- package/dist/local-model-executor.d.ts.map +1 -0
- package/dist/local-model-executor.js +201 -0
- package/dist/local-model-executor.js.map +1 -0
- package/dist/local-setup.d.ts +52 -0
- package/dist/local-setup.d.ts.map +1 -0
- package/dist/local-setup.js +254 -0
- package/dist/local-setup.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,6 +8,9 @@ import * as fs from 'fs';
|
|
|
8
8
|
import * as path from 'path';
|
|
9
9
|
import * as os from 'os';
|
|
10
10
|
import { GatewayClient } from './gateway-client.js';
|
|
11
|
+
import { executeLocalModel, verifyLocalModelServer } from './local-model-executor.js';
|
|
12
|
+
import { checkOllamaInstallation, installOllama, startOllamaServer, downloadModel, verifyLocalExecution } from './local-setup.js';
|
|
13
|
+
import { loadSession, clearSession, createSession, isSessionValid, getSessionTimeRemaining, getUserAgentsPath, getUserToolsPath } from './auth.js';
|
|
11
14
|
// ANSI colors
|
|
12
15
|
const colors = {
|
|
13
16
|
reset: '\x1b[0m',
|
|
@@ -23,13 +26,23 @@ const colors = {
|
|
|
23
26
|
brightGreen: '\x1b[1m\x1b[32m'
|
|
24
27
|
};
|
|
25
28
|
const { cyan, green, yellow, blue, magenta, red, gray, bright, reset, dim, brightGreen } = colors;
|
|
26
|
-
let client;
|
|
29
|
+
let client = null;
|
|
27
30
|
let systemReady = false;
|
|
31
|
+
let gatewayConnected = false;
|
|
32
|
+
let localMode = false; // Run without gateway (local-only)
|
|
33
|
+
let currentUser = null; // Current logged-in user
|
|
34
|
+
let sessionCheckInterval = null; // Session expiry checker
|
|
28
35
|
// Gateway URL - configurable via GATEWAY_URL environment variable or config file
|
|
29
|
-
// Default: Official 4Runr server
|
|
36
|
+
// Default: Official 4Runr server (but connection requires login)
|
|
30
37
|
// Override: Set GATEWAY_URL environment variable
|
|
31
38
|
// Local dev: Set GATEWAY_URL=http://localhost:3001
|
|
32
39
|
let gatewayUrl = process.env.GATEWAY_URL || 'http://44.222.212.152';
|
|
40
|
+
// Parse command line args
|
|
41
|
+
const args = process.argv.slice(2);
|
|
42
|
+
if (args.includes('--local')) {
|
|
43
|
+
localMode = true;
|
|
44
|
+
gatewayUrl = '';
|
|
45
|
+
}
|
|
33
46
|
// Chat mode state
|
|
34
47
|
let chatMode = false;
|
|
35
48
|
let chatAgent = null;
|
|
@@ -51,8 +64,11 @@ function getConfigDir() {
|
|
|
51
64
|
}
|
|
52
65
|
return configDir;
|
|
53
66
|
}
|
|
54
|
-
// Get agents file path
|
|
67
|
+
// Get agents file path (user-specific if logged in)
|
|
55
68
|
function getAgentsFilePath() {
|
|
69
|
+
if (currentUser) {
|
|
70
|
+
return getUserAgentsPath(currentUser.username);
|
|
71
|
+
}
|
|
56
72
|
return path.join(getConfigDir(), 'agents.json');
|
|
57
73
|
}
|
|
58
74
|
// Load custom agents from file
|
|
@@ -82,8 +98,11 @@ function saveCustomAgents() {
|
|
|
82
98
|
console.error(`Failed to save agents: ${error.message}`);
|
|
83
99
|
}
|
|
84
100
|
}
|
|
85
|
-
// Get tools file path
|
|
101
|
+
// Get tools file path (user-specific if logged in)
|
|
86
102
|
function getToolsFilePath() {
|
|
103
|
+
if (currentUser) {
|
|
104
|
+
return getUserToolsPath(currentUser.username);
|
|
105
|
+
}
|
|
87
106
|
return path.join(getConfigDir(), 'tools.json');
|
|
88
107
|
}
|
|
89
108
|
// Load custom tools from file
|
|
@@ -143,41 +162,90 @@ ${reset}`);
|
|
|
143
162
|
await progress(['gateway', 'sentinel', 'shield', 'devkit', 'metrics', 'ai-providers']);
|
|
144
163
|
console.log(`${gray}[BOOT] Starting services...${reset}`);
|
|
145
164
|
await sleep(200);
|
|
146
|
-
// Check
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
// Check for existing session
|
|
166
|
+
const savedSession = loadSession();
|
|
167
|
+
if (savedSession && isSessionValid(savedSession)) {
|
|
168
|
+
currentUser = savedSession;
|
|
169
|
+
console.log(`${dim}[BOOT] Session restored: ${green}${savedSession.username}${reset}${dim} (${getSessionTimeRemaining(savedSession)}m remaining)${reset}`);
|
|
170
|
+
// Try to reconnect to gateway
|
|
171
|
+
if (!localMode && (savedSession.gatewayUrl || gatewayUrl)) {
|
|
172
|
+
const urlToUse = savedSession.gatewayUrl || gatewayUrl;
|
|
173
|
+
process.stdout.write(`${gray}[BOOT] Reconnecting to gateway... ${reset}`);
|
|
174
|
+
try {
|
|
175
|
+
client = new GatewayClient({ gatewayUrl: urlToUse });
|
|
176
|
+
const health = await client.health();
|
|
177
|
+
console.log(`${green}✓${reset}`);
|
|
178
|
+
gatewayConnected = true;
|
|
179
|
+
gatewayUrl = urlToUse;
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
console.log(`${yellow}✗${reset} ${dim}(offline)${reset}`);
|
|
183
|
+
gatewayConnected = false;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// No session - user needs to login
|
|
189
|
+
if (localMode) {
|
|
190
|
+
console.log(`${dim}[BOOT] Mode: ${green}Local-only${reset} ${dim}(no login required)${reset}`);
|
|
166
191
|
}
|
|
167
|
-
|
|
168
|
-
console.log(`${
|
|
192
|
+
else {
|
|
193
|
+
console.log(`${dim}[BOOT] Not connected${reset}`);
|
|
194
|
+
console.log(`${dim}Use ${bright}connect <username>${reset}${dim} to access mainframe${reset}`);
|
|
195
|
+
console.log(`${dim}Or run in ${bright}--local${reset}${dim} mode for offline use${reset}`);
|
|
169
196
|
}
|
|
170
|
-
await sleep(300);
|
|
171
|
-
console.log(`\n${green}${bright}[READY] 4Runr OS is ready!${reset}\n`);
|
|
172
|
-
systemReady = true;
|
|
173
197
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
console.log(`${
|
|
178
|
-
|
|
198
|
+
await sleep(300);
|
|
199
|
+
console.log(`\n${green}${bright}[READY] 4Runr OS is ready!${reset}`);
|
|
200
|
+
if (currentUser) {
|
|
201
|
+
console.log(`${dim}Connected as: ${green}${currentUser.username}${reset}${dim} | Session: ${getSessionTimeRemaining(currentUser)}m${reset}`);
|
|
202
|
+
}
|
|
203
|
+
else if (!localMode) {
|
|
204
|
+
console.log(`${dim}Mode: ${yellow}Not connected${reset} ${dim}(local mode only)${reset}`);
|
|
205
|
+
console.log(`${dim}Type ${bright}connect <username>${reset}${dim} to access mainframe${reset}`);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.log(`${dim}Mode: ${green}Local-only${reset} ${dim}(no remote features)${reset}`);
|
|
209
|
+
}
|
|
210
|
+
console.log();
|
|
211
|
+
systemReady = true;
|
|
212
|
+
// Start session expiry checker
|
|
213
|
+
if (currentUser && !localMode) {
|
|
214
|
+
startSessionChecker();
|
|
179
215
|
}
|
|
180
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Start session expiry checker
|
|
219
|
+
*/
|
|
220
|
+
function startSessionChecker() {
|
|
221
|
+
// Check every 5 minutes
|
|
222
|
+
sessionCheckInterval = setInterval(() => {
|
|
223
|
+
if (currentUser && !isSessionValid(currentUser)) {
|
|
224
|
+
console.log(`\n${yellow}[ ${brightGreen}SESSION${reset}${yellow} ] Link expired${reset}`);
|
|
225
|
+
console.log(`${dim}Reconnect: ${bright}connect <username>${reset}\n`);
|
|
226
|
+
handleLogout();
|
|
227
|
+
}
|
|
228
|
+
}, 5 * 60 * 1000);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Stop session checker
|
|
232
|
+
*/
|
|
233
|
+
function stopSessionChecker() {
|
|
234
|
+
if (sessionCheckInterval) {
|
|
235
|
+
clearInterval(sessionCheckInterval);
|
|
236
|
+
sessionCheckInterval = null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Handle logout
|
|
241
|
+
*/
|
|
242
|
+
function handleLogout() {
|
|
243
|
+
stopSessionChecker();
|
|
244
|
+
clearSession();
|
|
245
|
+
currentUser = null;
|
|
246
|
+
gatewayConnected = false;
|
|
247
|
+
client = null;
|
|
248
|
+
}
|
|
181
249
|
async function progress(items) {
|
|
182
250
|
for (const item of items) {
|
|
183
251
|
process.stdout.write(`${gray} - ${item}${reset}`);
|
|
@@ -255,8 +323,14 @@ const commands = {
|
|
|
255
323
|
console.log(` ${cyan}get${reset} Get run details`);
|
|
256
324
|
console.log(` ${cyan}list${reset} List all runs`);
|
|
257
325
|
console.log();
|
|
326
|
+
console.log(`${magenta}Connection:${reset}`);
|
|
327
|
+
console.log(` ${cyan}connect${reset} Connect to mainframe (required for remote features)`);
|
|
328
|
+
console.log(` ${cyan}disconnect${reset} Disconnect from mainframe`);
|
|
329
|
+
console.log(` ${cyan}whoami${reset} Show current connection and session info`);
|
|
330
|
+
console.log();
|
|
258
331
|
console.log(`${magenta}System:${reset}`);
|
|
259
332
|
console.log(` ${cyan}status${reset} Show system status`);
|
|
333
|
+
console.log(` ${cyan}gateway${reset} Manage gateway connection (connect/disconnect/status)`);
|
|
260
334
|
console.log(` ${cyan}sentinel${reset} Show Sentinel monitoring`);
|
|
261
335
|
console.log(` ${cyan}metrics${reset} Show system metrics`);
|
|
262
336
|
console.log(` ${cyan}clear${reset} Clear the screen`);
|
|
@@ -497,11 +571,96 @@ const commands = {
|
|
|
497
571
|
console.log(`${red}Invalid choice${reset}\n`);
|
|
498
572
|
return;
|
|
499
573
|
}
|
|
500
|
-
|
|
574
|
+
// Integrated setup - automatically install and configure
|
|
575
|
+
console.log(`\n${bright}Setting up local model environment...${reset}`);
|
|
576
|
+
if (localModelProvider === 'ollama') {
|
|
577
|
+
// Check if Ollama is installed
|
|
578
|
+
const ollamaCheck = await checkOllamaInstallation();
|
|
579
|
+
if (!ollamaCheck.ollamaInstalled) {
|
|
580
|
+
console.log(`${yellow}Ollama not found. Installing automatically...${reset}`);
|
|
581
|
+
const installResult = await installOllama();
|
|
582
|
+
if (!installResult.success) {
|
|
583
|
+
console.log(`${red}✗ ${installResult.message}${reset}\n`);
|
|
584
|
+
const continueChoice = await prompt(rl, `${yellow}Continue anyway? (y/n):${reset} `);
|
|
585
|
+
if (continueChoice?.toLowerCase() !== 'y') {
|
|
586
|
+
console.log(`${gray}Agent creation cancelled${reset}\n`);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
console.log(`${green}✓ ${installResult.message}${reset}`);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
// Start server if not running
|
|
595
|
+
const serverCheck = await checkOllamaInstallation();
|
|
596
|
+
if (!serverCheck.success) {
|
|
597
|
+
console.log(`${dim}Starting Ollama server...${reset}`);
|
|
598
|
+
const startResult = await startOllamaServer();
|
|
599
|
+
if (startResult.success) {
|
|
600
|
+
console.log(`${green}✓ ${startResult.message}${reset}`);
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
console.log(`${yellow}⚠ ${startResult.message}${reset}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// Get available models
|
|
607
|
+
const finalCheck = await checkOllamaInstallation();
|
|
608
|
+
if (finalCheck.modelsAvailable && finalCheck.modelsAvailable.length > 0) {
|
|
609
|
+
console.log(`${green}✓ Ollama is ready${reset}`);
|
|
610
|
+
console.log(`${dim}Available models: ${finalCheck.modelsAvailable.join(', ')}${reset}`);
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
console.log(`${yellow}⚠ No models installed yet${reset}`);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
else if (localModelProvider === 'lm-studio') {
|
|
617
|
+
// LM Studio - check if running
|
|
618
|
+
const verification = await verifyLocalModelServer('lm-studio', localModelUrl);
|
|
619
|
+
if (!verification.available) {
|
|
620
|
+
console.log(`${yellow}⚠ LM Studio server not running${reset}`);
|
|
621
|
+
console.log(`${dim}Please start LM Studio and click "Start Server" in the Chat tab${reset}`);
|
|
622
|
+
const continueChoice = await prompt(rl, `${yellow}Continue anyway? (y/n):${reset} `);
|
|
623
|
+
if (continueChoice?.toLowerCase() !== 'y') {
|
|
624
|
+
console.log(`${gray}Agent creation cancelled${reset}\n`);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
console.log(`${green}✓ LM Studio server is running${reset}`);
|
|
630
|
+
if (verification.models && verification.models.length > 0) {
|
|
631
|
+
console.log(`${dim}Available models: ${verification.models.join(', ')}${reset}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// Get model name
|
|
636
|
+
localModelName = await prompt(rl, `\n${cyan}Model name (e.g., llama2, mistral, gpt-3.5-turbo):${reset} `);
|
|
501
637
|
if (!localModelName) {
|
|
502
638
|
console.log(`${red}Model name required${reset}\n`);
|
|
503
639
|
return;
|
|
504
640
|
}
|
|
641
|
+
// Auto-download model if using Ollama and model not found
|
|
642
|
+
if (localModelProvider === 'ollama') {
|
|
643
|
+
const finalCheck = await checkOllamaInstallation();
|
|
644
|
+
if (finalCheck.modelsAvailable && !finalCheck.modelsAvailable.includes(localModelName)) {
|
|
645
|
+
console.log(`\n${yellow}Model '${localModelName}' not found${reset}`);
|
|
646
|
+
const downloadChoice = await prompt(rl, `${cyan}Download it now? (y/n):${reset} `);
|
|
647
|
+
if (downloadChoice?.toLowerCase() === 'y') {
|
|
648
|
+
console.log(`\n${dim}Downloading model (this may take several minutes)...${reset}`);
|
|
649
|
+
const downloadResult = await downloadModel(localModelName);
|
|
650
|
+
if (downloadResult.success) {
|
|
651
|
+
console.log(`${green}✓ ${downloadResult.message}${reset}`);
|
|
652
|
+
}
|
|
653
|
+
else {
|
|
654
|
+
console.log(`${red}✗ ${downloadResult.message}${reset}`);
|
|
655
|
+
const continueChoice = await prompt(rl, `${yellow}Continue anyway? (y/n):${reset} `);
|
|
656
|
+
if (continueChoice?.toLowerCase() !== 'y') {
|
|
657
|
+
console.log(`${gray}Agent creation cancelled${reset}\n`);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
}
|
|
505
664
|
baseAgent = `local:${localModelProvider}:${localModelName}`;
|
|
506
665
|
}
|
|
507
666
|
else {
|
|
@@ -718,7 +877,13 @@ const commands = {
|
|
|
718
877
|
let agentConfig = null;
|
|
719
878
|
if (customAgent) {
|
|
720
879
|
// Use custom agent
|
|
721
|
-
|
|
880
|
+
// For local models, use gpt-3.5-turbo as the base executor (gateway handles local models)
|
|
881
|
+
if (customAgent.useLocalModel) {
|
|
882
|
+
actualAgentId = 'gpt-3.5-turbo';
|
|
883
|
+
}
|
|
884
|
+
else {
|
|
885
|
+
actualAgentId = customAgent.baseAgent;
|
|
886
|
+
}
|
|
722
887
|
agentConfig = customAgent;
|
|
723
888
|
}
|
|
724
889
|
else {
|
|
@@ -760,6 +925,23 @@ const commands = {
|
|
|
760
925
|
usage: 'status',
|
|
761
926
|
handler: async () => {
|
|
762
927
|
console.log(`\n${bright}System Status:${reset}`);
|
|
928
|
+
// Connection status
|
|
929
|
+
if (currentUser) {
|
|
930
|
+
console.log(` ${green}Link:${reset} Connected as ${currentUser.username}`);
|
|
931
|
+
console.log(` ${green}Session:${reset} ${getSessionTimeRemaining(currentUser)}m remaining`);
|
|
932
|
+
}
|
|
933
|
+
else {
|
|
934
|
+
console.log(` ${yellow}Link:${reset} Not connected`);
|
|
935
|
+
}
|
|
936
|
+
// Gateway status
|
|
937
|
+
if (!client || !gatewayConnected) {
|
|
938
|
+
console.log(` ${yellow}Mainframe:${reset} Offline`);
|
|
939
|
+
if (!currentUser && !localMode) {
|
|
940
|
+
console.log(` ${dim}Use ${bright}connect <username>${reset}${dim} to access mainframe${reset}`);
|
|
941
|
+
}
|
|
942
|
+
console.log();
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
763
945
|
const health = await client.health();
|
|
764
946
|
console.log(` Gateway: ${green}✓${reset} alive`);
|
|
765
947
|
console.log(` Database: ${green}✓${reset} ${health.persistence}`);
|
|
@@ -780,6 +962,10 @@ const commands = {
|
|
|
780
962
|
description: 'Create a new run',
|
|
781
963
|
usage: 'create <name> [agent-id]',
|
|
782
964
|
handler: async (args) => {
|
|
965
|
+
if (!client || !gatewayConnected) {
|
|
966
|
+
console.log(`${red}Gateway not connected. Use ${bright}gateway connect${reset}${red} first.${reset}\n`);
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
783
969
|
if (args.length === 0) {
|
|
784
970
|
console.log(`${red}Usage: create <name> [agent-id]${reset}\n`);
|
|
785
971
|
return;
|
|
@@ -806,6 +992,10 @@ const commands = {
|
|
|
806
992
|
description: 'Start a run',
|
|
807
993
|
usage: 'start <run-id>',
|
|
808
994
|
handler: async (args) => {
|
|
995
|
+
if (!client || !gatewayConnected) {
|
|
996
|
+
console.log(`${red}Gateway not connected. Use ${bright}gateway connect${reset}${red} first.${reset}\n`);
|
|
997
|
+
return;
|
|
998
|
+
}
|
|
809
999
|
if (args.length === 0) {
|
|
810
1000
|
console.log(`${red}Usage: start <run-id>${reset}\n`);
|
|
811
1001
|
return;
|
|
@@ -826,6 +1016,10 @@ const commands = {
|
|
|
826
1016
|
description: 'Get run details',
|
|
827
1017
|
usage: 'get <run-id>',
|
|
828
1018
|
handler: async (args) => {
|
|
1019
|
+
if (!client || !gatewayConnected) {
|
|
1020
|
+
console.log(`${red}Gateway not connected. Use ${bright}gateway connect${reset}${red} first.${reset}\n`);
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
829
1023
|
if (args.length === 0) {
|
|
830
1024
|
console.log(`${red}Usage: get <run-id>${reset}\n`);
|
|
831
1025
|
return;
|
|
@@ -851,6 +1045,10 @@ const commands = {
|
|
|
851
1045
|
description: 'List all runs',
|
|
852
1046
|
usage: 'list [limit]',
|
|
853
1047
|
handler: async (args) => {
|
|
1048
|
+
if (!client || !gatewayConnected) {
|
|
1049
|
+
console.log(`${red}Gateway not connected. Use ${bright}gateway connect${reset}${red} first.${reset}\n`);
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
854
1052
|
const limit = args[0] ? parseInt(args[0]) : 10;
|
|
855
1053
|
const runs = await client.runs.list({ limit });
|
|
856
1054
|
if (runs.length === 0) {
|
|
@@ -895,6 +1093,10 @@ const commands = {
|
|
|
895
1093
|
description: 'Show system metrics',
|
|
896
1094
|
usage: 'metrics',
|
|
897
1095
|
handler: async () => {
|
|
1096
|
+
if (!client || !gatewayConnected) {
|
|
1097
|
+
console.log(`${red}Gateway not connected. Use ${bright}gateway connect${reset}${red} first.${reset}\n`);
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
898
1100
|
console.log(`${gray}Fetching metrics...${reset}\n`);
|
|
899
1101
|
try {
|
|
900
1102
|
const metrics = await client.metrics();
|
|
@@ -925,6 +1127,147 @@ const commands = {
|
|
|
925
1127
|
process.exit(0);
|
|
926
1128
|
}
|
|
927
1129
|
},
|
|
1130
|
+
connect: {
|
|
1131
|
+
description: 'Connect to mainframe (required for remote features)',
|
|
1132
|
+
usage: 'connect <username>',
|
|
1133
|
+
handler: async (args, rl) => {
|
|
1134
|
+
if (localMode) {
|
|
1135
|
+
console.log(`${yellow}Cannot connect in local-only mode${reset}\n`);
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
if (currentUser) {
|
|
1139
|
+
console.log(`${yellow}Already connected as ${currentUser.username}${reset}`);
|
|
1140
|
+
console.log(`${dim}Use ${bright}disconnect${reset}${dim} first to switch users${reset}\n`);
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
if (args.length === 0) {
|
|
1144
|
+
console.log(`${red}Usage: connect <username>${reset}\n`);
|
|
1145
|
+
return;
|
|
1146
|
+
}
|
|
1147
|
+
const username = args.join(' ').trim();
|
|
1148
|
+
console.log(`\n${dim}[ ${brightGreen}CONNECT${reset}${dim} ] Establishing link to mainframe...${reset}`);
|
|
1149
|
+
await sleep(500);
|
|
1150
|
+
console.log(`${dim}[ ${brightGreen}AUTH${reset}${dim} ] Authenticating ${cyan}${username}${reset}${dim}...${reset}`);
|
|
1151
|
+
await sleep(300);
|
|
1152
|
+
// Create session
|
|
1153
|
+
currentUser = createSession(username, gatewayUrl);
|
|
1154
|
+
// Load user-specific data
|
|
1155
|
+
loadCustomAgents();
|
|
1156
|
+
loadCustomTools();
|
|
1157
|
+
// Try to connect to gateway
|
|
1158
|
+
if (gatewayUrl) {
|
|
1159
|
+
try {
|
|
1160
|
+
client = new GatewayClient({ gatewayUrl });
|
|
1161
|
+
const health = await client.health();
|
|
1162
|
+
gatewayConnected = true;
|
|
1163
|
+
console.log(`${green}[ ${brightGreen}CONNECTED${reset}${green} ] Link established${reset}`);
|
|
1164
|
+
console.log(`${dim}User: ${green}${username}${reset}${dim} | Session: ${getSessionTimeRemaining(currentUser)}m${reset}\n`);
|
|
1165
|
+
// Start session checker
|
|
1166
|
+
startSessionChecker();
|
|
1167
|
+
}
|
|
1168
|
+
catch (error) {
|
|
1169
|
+
console.log(`${yellow}[ ${brightGreen}PARTIAL${reset}${yellow} ] Connected, but mainframe unavailable${reset}`);
|
|
1170
|
+
console.log(`${dim}Local features only${reset}\n`);
|
|
1171
|
+
gatewayConnected = false;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
console.log(`${green}[ ${brightGreen}CONNECTED${reset}${green} ] Local mode${reset}\n`);
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
},
|
|
1179
|
+
disconnect: {
|
|
1180
|
+
description: 'Disconnect from mainframe',
|
|
1181
|
+
usage: 'disconnect',
|
|
1182
|
+
handler: async () => {
|
|
1183
|
+
if (!currentUser) {
|
|
1184
|
+
console.log(`${yellow}Not connected${reset}\n`);
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
const username = currentUser.username;
|
|
1188
|
+
console.log(`\n${dim}[ ${brightGreen}DISCONNECT${reset}${dim} ] Terminating link for ${cyan}${username}${reset}${dim}...${reset}`);
|
|
1189
|
+
await sleep(300);
|
|
1190
|
+
handleLogout();
|
|
1191
|
+
console.log(`${green}[ ${brightGreen}DISCONNECTED${reset}${green} ] Link terminated${reset}`);
|
|
1192
|
+
console.log(`${dim}Use ${bright}connect <username>${reset}${dim} to reconnect${reset}\n`);
|
|
1193
|
+
}
|
|
1194
|
+
},
|
|
1195
|
+
whoami: {
|
|
1196
|
+
description: 'Show current connection and session info',
|
|
1197
|
+
usage: 'whoami',
|
|
1198
|
+
handler: async () => {
|
|
1199
|
+
console.log(`\n${bright}Connection Status:${reset}`);
|
|
1200
|
+
if (currentUser) {
|
|
1201
|
+
console.log(` ${green}User:${reset} ${currentUser.username}`);
|
|
1202
|
+
console.log(` ${green}Link:${reset} Connected`);
|
|
1203
|
+
console.log(` ${green}Session:${reset} ${getSessionTimeRemaining(currentUser)}m remaining`);
|
|
1204
|
+
console.log(` ${green}Mainframe:${reset} ${gatewayConnected ? 'Online' : 'Offline'}`);
|
|
1205
|
+
}
|
|
1206
|
+
else {
|
|
1207
|
+
console.log(` ${yellow}Link:${reset} Not connected`);
|
|
1208
|
+
console.log(` ${yellow}Mode:${reset} ${localMode ? 'Local-only' : 'Offline'}`);
|
|
1209
|
+
}
|
|
1210
|
+
console.log();
|
|
1211
|
+
}
|
|
1212
|
+
},
|
|
1213
|
+
gateway: {
|
|
1214
|
+
description: 'Manage gateway connection',
|
|
1215
|
+
usage: 'gateway [connect|disconnect|status] [url]',
|
|
1216
|
+
handler: async (args, rl) => {
|
|
1217
|
+
const action = args[0] || 'status';
|
|
1218
|
+
if (action === 'status') {
|
|
1219
|
+
console.log(`\n${bright}Gateway Status:${reset}`);
|
|
1220
|
+
if (localMode) {
|
|
1221
|
+
console.log(` ${yellow}Mode: Local-only (gateway disabled)${reset}`);
|
|
1222
|
+
}
|
|
1223
|
+
else if (gatewayConnected && client) {
|
|
1224
|
+
console.log(` ${green}Status: Connected${reset}`);
|
|
1225
|
+
console.log(` ${dim}URL: ${gatewayUrl}${reset}`);
|
|
1226
|
+
try {
|
|
1227
|
+
const health = await client.health();
|
|
1228
|
+
console.log(` ${green}✓ Gateway is responding${reset}`);
|
|
1229
|
+
}
|
|
1230
|
+
catch (e) {
|
|
1231
|
+
console.log(` ${red}✗ Gateway not responding${reset}`);
|
|
1232
|
+
gatewayConnected = false;
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
console.log(` ${yellow}Status: Disconnected (offline mode)${reset}`);
|
|
1237
|
+
console.log(` ${dim}Use ${bright}gateway connect${reset}${dim} to connect${reset}`);
|
|
1238
|
+
}
|
|
1239
|
+
console.log();
|
|
1240
|
+
}
|
|
1241
|
+
else if (action === 'connect') {
|
|
1242
|
+
const url = args[1] || gatewayUrl || 'http://44.222.212.152';
|
|
1243
|
+
console.log(`\n${dim}Connecting to gateway at ${url}...${reset}`);
|
|
1244
|
+
try {
|
|
1245
|
+
gatewayUrl = url;
|
|
1246
|
+
client = new GatewayClient({ gatewayUrl: url });
|
|
1247
|
+
const health = await client.health();
|
|
1248
|
+
console.log(`${green}✓ Connected to gateway${reset}`);
|
|
1249
|
+
console.log(`${dim}URL: ${url}${reset}\n`);
|
|
1250
|
+
gatewayConnected = true;
|
|
1251
|
+
localMode = false;
|
|
1252
|
+
}
|
|
1253
|
+
catch (error) {
|
|
1254
|
+
console.log(`${red}✗ Failed to connect: ${error.message}${reset}`);
|
|
1255
|
+
console.log(`${dim}Staying in offline mode${reset}\n`);
|
|
1256
|
+
gatewayConnected = false;
|
|
1257
|
+
}
|
|
1258
|
+
}
|
|
1259
|
+
else if (action === 'disconnect') {
|
|
1260
|
+
console.log(`\n${dim}Disconnecting from gateway...${reset}`);
|
|
1261
|
+
gatewayConnected = false;
|
|
1262
|
+
client = null;
|
|
1263
|
+
console.log(`${green}✓ Disconnected (offline mode active)${reset}\n`);
|
|
1264
|
+
}
|
|
1265
|
+
else {
|
|
1266
|
+
console.log(`${red}Unknown action: ${action}${reset}`);
|
|
1267
|
+
console.log(`${dim}Usage: gateway [connect|disconnect|status]${reset}\n`);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
},
|
|
928
1271
|
tools: {
|
|
929
1272
|
description: 'Manage tools for agents',
|
|
930
1273
|
usage: 'tools [list|create|edit|delete|test] [tool-name]',
|
|
@@ -1206,50 +1549,109 @@ async function startREPL() {
|
|
|
1206
1549
|
try {
|
|
1207
1550
|
// Get custom agent config if available
|
|
1208
1551
|
const agentConfig = rl.chatAgentConfig;
|
|
1209
|
-
//
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
// Include custom agent settings
|
|
1217
|
-
...(agentConfig?.systemPrompt && { systemPrompt: agentConfig.systemPrompt }),
|
|
1218
|
-
...(agentConfig?.temperature !== undefined && { temperature: agentConfig.temperature }),
|
|
1219
|
-
...(agentConfig?.maxTokens !== undefined && { maxTokens: agentConfig.maxTokens }),
|
|
1220
|
-
...(conversationHistory.length > 0 && { conversationHistory })
|
|
1221
|
-
}
|
|
1552
|
+
// Check if this is a local model agent - execute directly (bypass gateway)
|
|
1553
|
+
if (agentConfig?.useLocalModel && agentConfig.localModelProvider && agentConfig.localModelName) {
|
|
1554
|
+
// Execute locally - this is the REAL local execution
|
|
1555
|
+
const messages = [];
|
|
1556
|
+
// Add system prompt
|
|
1557
|
+
if (agentConfig.systemPrompt) {
|
|
1558
|
+
messages.push({ role: 'system', content: agentConfig.systemPrompt });
|
|
1222
1559
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1560
|
+
// Add conversation history
|
|
1561
|
+
if (conversationHistory.length > 0) {
|
|
1562
|
+
messages.push(...conversationHistory);
|
|
1563
|
+
}
|
|
1564
|
+
// Add current message
|
|
1565
|
+
messages.push({ role: 'user', content: message });
|
|
1566
|
+
// Execute local model directly
|
|
1567
|
+
const localConfig = {
|
|
1568
|
+
provider: agentConfig.localModelProvider,
|
|
1569
|
+
model: agentConfig.localModelName,
|
|
1570
|
+
baseUrl: agentConfig.localModelUrl,
|
|
1571
|
+
temperature: agentConfig.temperature,
|
|
1572
|
+
maxTokens: agentConfig.maxTokens,
|
|
1573
|
+
topP: agentConfig.topP,
|
|
1574
|
+
frequencyPenalty: agentConfig.frequencyPenalty,
|
|
1575
|
+
presencePenalty: agentConfig.presencePenalty,
|
|
1576
|
+
};
|
|
1577
|
+
// PROOF: Verify execution is truly local before executing
|
|
1578
|
+
const localProof = await verifyLocalExecution();
|
|
1579
|
+
if (!localProof.isLocal) {
|
|
1580
|
+
console.log(`${red}⚠ WARNING: Local execution verification failed!${reset}`);
|
|
1581
|
+
console.log(`${yellow}This may indicate the request is going through a remote server.${reset}\n`);
|
|
1582
|
+
}
|
|
1583
|
+
const result = await executeLocalModel(localConfig, messages);
|
|
1584
|
+
// Clear thinking indicator
|
|
1585
|
+
process.stdout.write(`\r${' '.repeat(20)}\r`);
|
|
1236
1586
|
// Update conversation history
|
|
1237
1587
|
conversationHistory.push({ role: 'user', content: message });
|
|
1238
|
-
conversationHistory.push({ role: 'assistant', content:
|
|
1239
|
-
// Show response with
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
console.log(`${green}${friendlyName}:${reset} ${response}\n`);
|
|
1246
|
-
// Show usage if available
|
|
1247
|
-
if (output.usage) {
|
|
1248
|
-
console.log(`${gray}Tokens: ${output.usage.totalTokens || 'N/A'} | Cost: $${(output.cost || 0).toFixed(6)}${reset}\n`);
|
|
1588
|
+
conversationHistory.push({ role: 'assistant', content: result.result });
|
|
1589
|
+
// Show response with proof it's local
|
|
1590
|
+
console.log(`${green}${agentConfig.name}:${reset} ${result.result}\n`);
|
|
1591
|
+
// Show usage and proof
|
|
1592
|
+
if (result.usage) {
|
|
1593
|
+
console.log(`${gray}Tokens: ${result.usage.totalTokens || 'N/A'} | Model: ${result.model} | Cost: $0.000000 (local)${reset}`);
|
|
1594
|
+
console.log(`${dim}✓ Executed locally (${localProof.proof.executionPath}) | Response time: ${localProof.proof.responseTime}ms${reset}\n`);
|
|
1249
1595
|
}
|
|
1250
1596
|
}
|
|
1251
1597
|
else {
|
|
1252
|
-
|
|
1598
|
+
// Remote model - execute through gateway
|
|
1599
|
+
if (!client || !gatewayConnected) {
|
|
1600
|
+
console.log(`${red}Mainframe not connected. Use ${bright}connect <username>${reset}${red} for remote agents.${reset}\n`);
|
|
1601
|
+
rl.prompt();
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1604
|
+
const run = await client.runs.create({
|
|
1605
|
+
name: `${chatAgent}: ${message.substring(0, 50)}...`,
|
|
1606
|
+
input: {
|
|
1607
|
+
agent_id: chatAgent,
|
|
1608
|
+
data: {
|
|
1609
|
+
prompt: message,
|
|
1610
|
+
// Include custom agent settings
|
|
1611
|
+
...(agentConfig?.systemPrompt && { systemPrompt: agentConfig.systemPrompt }),
|
|
1612
|
+
...(agentConfig?.temperature !== undefined && { temperature: agentConfig.temperature }),
|
|
1613
|
+
...(agentConfig?.maxTokens !== undefined && { maxTokens: agentConfig.maxTokens }),
|
|
1614
|
+
// Advanced parameters
|
|
1615
|
+
...(agentConfig?.topP !== undefined && { topP: agentConfig.topP }),
|
|
1616
|
+
...(agentConfig?.frequencyPenalty !== undefined && { frequencyPenalty: agentConfig.frequencyPenalty }),
|
|
1617
|
+
...(agentConfig?.presencePenalty !== undefined && { presencePenalty: agentConfig.presencePenalty }),
|
|
1618
|
+
// Tools
|
|
1619
|
+
...(agentConfig?.tools && agentConfig.tools.length > 0 && { tools: agentConfig.tools }),
|
|
1620
|
+
// Always include conversation history for context
|
|
1621
|
+
conversationHistory: conversationHistory.length > 0 ? conversationHistory : []
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
});
|
|
1625
|
+
await client.runs.start(run.id);
|
|
1626
|
+
// Monitor execution
|
|
1627
|
+
let status = await client.runs.get(run.id);
|
|
1628
|
+
while (status.status === 'running' || status.status === 'queued') {
|
|
1629
|
+
await sleep(500);
|
|
1630
|
+
status = await client.runs.get(run.id);
|
|
1631
|
+
}
|
|
1632
|
+
// Clear thinking indicator
|
|
1633
|
+
process.stdout.write(`\r${' '.repeat(20)}\r`);
|
|
1634
|
+
if (status.output) {
|
|
1635
|
+
const output = status.output;
|
|
1636
|
+
const response = output.result || output.message || JSON.stringify(output, null, 2);
|
|
1637
|
+
// Update conversation history
|
|
1638
|
+
conversationHistory.push({ role: 'user', content: message });
|
|
1639
|
+
conversationHistory.push({ role: 'assistant', content: response });
|
|
1640
|
+
// Show response with friendly name
|
|
1641
|
+
const agentConfig = rl.chatAgentConfig;
|
|
1642
|
+
const friendlyName = agentConfig ? agentConfig.name :
|
|
1643
|
+
chatAgent === 'gpt-3.5-turbo' ? 'Assistant' :
|
|
1644
|
+
chatAgent === 'gpt-4' ? 'GPT-4' :
|
|
1645
|
+
chatAgent;
|
|
1646
|
+
console.log(`${green}${friendlyName}:${reset} ${response}\n`);
|
|
1647
|
+
// Show usage if available
|
|
1648
|
+
if (output.usage) {
|
|
1649
|
+
console.log(`${gray}Tokens: ${output.usage.totalTokens || 'N/A'} | Cost: $${(output.cost || 0).toFixed(6)}${reset}\n`);
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1652
|
+
else {
|
|
1653
|
+
console.log(`${yellow}No response received${reset}\n`);
|
|
1654
|
+
}
|
|
1253
1655
|
}
|
|
1254
1656
|
}
|
|
1255
1657
|
catch (error) {
|