agent-world 0.4.5 → 0.4.6
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/cli/index.js +89 -64
- package/dist/server/index.js +2 -5
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -38,22 +38,12 @@ import path from 'path';
|
|
|
38
38
|
import { fileURLToPath } from 'url';
|
|
39
39
|
import { program } from 'commander';
|
|
40
40
|
import readline from 'readline';
|
|
41
|
-
import { listWorlds, subscribeWorld, createCategoryLogger, LLMProvider,
|
|
41
|
+
import { listWorlds, subscribeWorld, createCategoryLogger, LLMProvider, enableStreaming, disableStreaming } from '../core/index.js';
|
|
42
42
|
import { getDefaultRootPath } from '../core/storage-factory.js';
|
|
43
43
|
import { processCLIInput } from './commands.js';
|
|
44
44
|
import { createStreamingState, handleWorldEventWithStreaming } from './stream.js';
|
|
45
45
|
import { configureLLMProvider } from '../core/llm-config.js';
|
|
46
|
-
//
|
|
47
|
-
initializeLogger({
|
|
48
|
-
globalLevel: 'error',
|
|
49
|
-
categoryLevels: {
|
|
50
|
-
cli: 'error',
|
|
51
|
-
core: 'error',
|
|
52
|
-
events: 'error',
|
|
53
|
-
llm: 'error'
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
// Create CLI category logger after initialization
|
|
46
|
+
// Create CLI category logger after logger auto-initialization
|
|
57
47
|
const logger = createCategoryLogger('cli');
|
|
58
48
|
function setupPromptTimer(globalState, rl, callback, delay = 2000) {
|
|
59
49
|
clearPromptTimer(globalState);
|
|
@@ -86,25 +76,6 @@ const boldCyan = (text) => `\x1b[1m\x1b[36m${text}\x1b[0m`;
|
|
|
86
76
|
const success = (text) => `${boldGreen('✓')} ${text}`;
|
|
87
77
|
const error = (text) => `${boldRed('✗')} ${text}`;
|
|
88
78
|
const bullet = (text) => `${gray('•')} ${text}`;
|
|
89
|
-
// Logger configuration
|
|
90
|
-
async function configureLogger(logLevel) {
|
|
91
|
-
// Use the centralized logger configuration from core
|
|
92
|
-
const level = (logLevel || 'error');
|
|
93
|
-
// Reinitialize logger with new configuration
|
|
94
|
-
initializeLogger({
|
|
95
|
-
globalLevel: level,
|
|
96
|
-
categoryLevels: {
|
|
97
|
-
cli: 'error', // Always keep CLI at error level
|
|
98
|
-
core: level, // Core modules use global level
|
|
99
|
-
events: 'error', // Keep events at error level (too verbose)
|
|
100
|
-
llm: level, // LLM module uses global level
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
// Only log the debug message if we're actually at debug level for global
|
|
104
|
-
if (level === 'debug' || level === 'trace') {
|
|
105
|
-
logger.debug(`Global log level set to: ${level}, CLI log level: error`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
79
|
// LLM Provider configuration from environment variables
|
|
109
80
|
function configureLLMProvidersFromEnv() {
|
|
110
81
|
// OpenAI
|
|
@@ -170,6 +141,21 @@ function configureLLMProvidersFromEnv() {
|
|
|
170
141
|
}
|
|
171
142
|
// Get default root path from storage-factory (no local defaults)
|
|
172
143
|
const DEFAULT_ROOT_PATH = getDefaultRootPath();
|
|
144
|
+
// Helper to print CLI results in a user-friendly way
|
|
145
|
+
function printCLIResult(result) {
|
|
146
|
+
if (result.success) {
|
|
147
|
+
if (result.message)
|
|
148
|
+
console.log(success(result.message));
|
|
149
|
+
if (result.data && typeof result.data === 'string')
|
|
150
|
+
console.log(result.data);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
if (result.message)
|
|
154
|
+
console.log(error(result.message));
|
|
155
|
+
if (result.error && result.error !== result.message)
|
|
156
|
+
console.log(error(result.error));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
173
159
|
// Pipeline mode execution with timer-based cleanup
|
|
174
160
|
async function runPipelineMode(options, messageFromArgs) {
|
|
175
161
|
const rootPath = options.root || DEFAULT_ROOT_PATH;
|
|
@@ -183,8 +169,12 @@ async function runPipelineMode(options, messageFromArgs) {
|
|
|
183
169
|
onWorldEvent: (eventType, eventData) => {
|
|
184
170
|
if (eventData.content && eventData.content.includes('Success message sent'))
|
|
185
171
|
return;
|
|
186
|
-
if ((eventType === 'system' || eventType === 'world') && eventData.message) {
|
|
187
|
-
|
|
172
|
+
if ((eventType === 'system' || eventType === 'world') && (eventData.message || eventData.content)) {
|
|
173
|
+
// existing logic
|
|
174
|
+
}
|
|
175
|
+
else if (eventType === 'message' && eventData.sender === 'system') {
|
|
176
|
+
const msg = eventData.content;
|
|
177
|
+
console.log(`${boldRed('● system:')} ${msg}`);
|
|
188
178
|
}
|
|
189
179
|
if (eventType === 'sse' && eventData.content) {
|
|
190
180
|
setupExitTimer(5000);
|
|
@@ -222,7 +212,7 @@ async function runPipelineMode(options, messageFromArgs) {
|
|
|
222
212
|
process.exit(1);
|
|
223
213
|
}
|
|
224
214
|
const result = await processCLIInput(options.command, world, rootPath, 'HUMAN');
|
|
225
|
-
|
|
215
|
+
printCLIResult(result);
|
|
226
216
|
// Only set timer if sending message to world (not for commands)
|
|
227
217
|
if (!options.command.startsWith('/') && world) {
|
|
228
218
|
setupExitTimer();
|
|
@@ -245,7 +235,7 @@ async function runPipelineMode(options, messageFromArgs) {
|
|
|
245
235
|
process.exit(1);
|
|
246
236
|
}
|
|
247
237
|
const result = await processCLIInput(messageFromArgs, world, rootPath, 'HUMAN');
|
|
248
|
-
|
|
238
|
+
printCLIResult(result);
|
|
249
239
|
// Set timer with longer delay for message processing (always needed for messages)
|
|
250
240
|
setupExitTimer(8000);
|
|
251
241
|
if (!result.success) {
|
|
@@ -265,7 +255,7 @@ async function runPipelineMode(options, messageFromArgs) {
|
|
|
265
255
|
process.exit(1);
|
|
266
256
|
}
|
|
267
257
|
const result = await processCLIInput(input.trim(), world, rootPath, 'HUMAN');
|
|
268
|
-
|
|
258
|
+
printCLIResult(result);
|
|
269
259
|
// Set timer with longer delay for message processing (always needed for stdin messages)
|
|
270
260
|
setupExitTimer(8000);
|
|
271
261
|
if (!result.success) {
|
|
@@ -312,8 +302,12 @@ function handleWorldEvent(eventType, eventData, streaming, globalState, rl) {
|
|
|
312
302
|
}
|
|
313
303
|
if (eventData.content && eventData.content.includes('Success message sent'))
|
|
314
304
|
return;
|
|
315
|
-
if ((eventType === 'system' || eventType === 'world') && eventData.message) {
|
|
316
|
-
|
|
305
|
+
if ((eventType === 'system' || eventType === 'world') && (eventData.message || eventData.content)) {
|
|
306
|
+
// existing logic
|
|
307
|
+
}
|
|
308
|
+
else if (eventType === 'message' && eventData.sender === 'system') {
|
|
309
|
+
const msg = eventData.content;
|
|
310
|
+
console.log(`${boldRed('● system:')} ${msg}`);
|
|
317
311
|
}
|
|
318
312
|
}
|
|
319
313
|
// World discovery and selection
|
|
@@ -445,7 +439,9 @@ async function runInteractiveMode(options) {
|
|
|
445
439
|
}
|
|
446
440
|
// Show usage tips
|
|
447
441
|
console.log(`\n${gray('Tips:')}`);
|
|
448
|
-
console.log(` ${bullet(gray('
|
|
442
|
+
console.log(` ${bullet(gray('Short commands:'))} ${cyan('/list')}, ${cyan('/show agent1')}, ${cyan('/edit agent1')}, ${cyan('/del agent1')}`);
|
|
443
|
+
console.log(` ${bullet(gray('Context-sensitive:'))} ${cyan('/list')} ${gray('shows agents if world selected, worlds otherwise')}`);
|
|
444
|
+
console.log(` ${bullet(gray('Legacy commands:'))} ${cyan('/clear agent1')}, ${cyan('/clear all')}, ${cyan('/add MyAgent')}`);
|
|
449
445
|
console.log(` ${bullet(gray('Use'))} ${cyan('/select')} ${gray('to choose a different world')}`);
|
|
450
446
|
console.log(` ${bullet(gray('Type messages to send to agents'))}`);
|
|
451
447
|
console.log(` ${bullet(gray('Use'))} ${cyan('/quit')} ${gray('or')} ${cyan('/exit')} ${gray('to exit, or press')} ${boldYellow('Ctrl+C')}`);
|
|
@@ -458,23 +454,39 @@ async function runInteractiveMode(options) {
|
|
|
458
454
|
rl.prompt();
|
|
459
455
|
return;
|
|
460
456
|
}
|
|
457
|
+
// Check for exit commands before anything else
|
|
458
|
+
const isExitCommand = trimmedInput.toLowerCase() === '/exit' || trimmedInput.toLowerCase() === '/quit';
|
|
459
|
+
if (isExitCommand) {
|
|
460
|
+
if (isExiting)
|
|
461
|
+
return;
|
|
462
|
+
isExiting = true;
|
|
463
|
+
// Clear any existing timers immediately
|
|
464
|
+
clearPromptTimer(globalState);
|
|
465
|
+
if (streaming.stopWait)
|
|
466
|
+
streaming.stopWait();
|
|
467
|
+
console.log(`\n${boldCyan('Goodbye!')}`);
|
|
468
|
+
if (worldState)
|
|
469
|
+
cleanupWorldSubscription(worldState);
|
|
470
|
+
rl.close();
|
|
471
|
+
process.exit(0);
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
461
474
|
console.log(`\n${boldYellow('● you:')} ${trimmedInput}`);
|
|
462
475
|
try {
|
|
463
476
|
const result = await processCLIInput(trimmedInput, worldState?.world || null, rootPath, 'HUMAN');
|
|
464
|
-
// Handle exit commands
|
|
477
|
+
// Handle exit commands from result (redundant, but keep for safety)
|
|
465
478
|
if (result.data?.exit) {
|
|
466
479
|
if (isExiting)
|
|
467
480
|
return; // Prevent duplicate exit handling
|
|
468
481
|
isExiting = true;
|
|
469
|
-
|
|
470
|
-
if (streaming.stopWait)
|
|
482
|
+
clearPromptTimer(globalState);
|
|
483
|
+
if (streaming.stopWait)
|
|
471
484
|
streaming.stopWait();
|
|
472
|
-
}
|
|
473
485
|
console.log(`\n${boldCyan('Goodbye!')}`);
|
|
474
|
-
if (worldState)
|
|
486
|
+
if (worldState)
|
|
475
487
|
cleanupWorldSubscription(worldState);
|
|
476
|
-
}
|
|
477
488
|
rl.close();
|
|
489
|
+
process.exit(0);
|
|
478
490
|
return;
|
|
479
491
|
}
|
|
480
492
|
// Handle world selection command
|
|
@@ -521,7 +533,23 @@ async function runInteractiveMode(options) {
|
|
|
521
533
|
console.log(success(result.message));
|
|
522
534
|
}
|
|
523
535
|
if (result.data && !(result.data.sender === 'HUMAN')) {
|
|
524
|
-
|
|
536
|
+
// Print a concise summary of result.data if present and not already in message
|
|
537
|
+
if (result.data) {
|
|
538
|
+
if (typeof result.data === 'string') {
|
|
539
|
+
console.log(`${boldMagenta('Data:')} ${result.data}`);
|
|
540
|
+
}
|
|
541
|
+
else if (result.data.name) {
|
|
542
|
+
// If it's an agent or world object
|
|
543
|
+
console.log(`${boldMagenta('Data:')} ${result.data.name}`);
|
|
544
|
+
}
|
|
545
|
+
else if (Array.isArray(result.data)) {
|
|
546
|
+
console.log(`${boldMagenta('Data:')} ${result.data.length} items`);
|
|
547
|
+
}
|
|
548
|
+
else {
|
|
549
|
+
// Fallback: print keys
|
|
550
|
+
console.log(`${boldMagenta('Data:')} ${Object.keys(result.data).join(', ')}`);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
525
553
|
}
|
|
526
554
|
// Refresh world if needed
|
|
527
555
|
if (result.refreshWorld && currentWorldName && worldState) {
|
|
@@ -542,13 +570,8 @@ async function runInteractiveMode(options) {
|
|
|
542
570
|
}
|
|
543
571
|
// Set timer based on input type: commands get short delay, messages get longer delay
|
|
544
572
|
const isCommand = trimmedInput.startsWith('/');
|
|
545
|
-
const isExitCommand = trimmedInput.toLowerCase() === '/exit' || trimmedInput.toLowerCase() === '/quit';
|
|
546
573
|
const isSelectCommand = trimmedInput.toLowerCase() === '/select';
|
|
547
|
-
if (
|
|
548
|
-
// For exit commands, don't set any timer - exit should be immediate
|
|
549
|
-
return;
|
|
550
|
-
}
|
|
551
|
-
else if (isSelectCommand) {
|
|
574
|
+
if (isSelectCommand) {
|
|
552
575
|
// For select command, prompt is already shown in the handler
|
|
553
576
|
return;
|
|
554
577
|
}
|
|
@@ -565,27 +588,26 @@ async function runInteractiveMode(options) {
|
|
|
565
588
|
if (isExiting)
|
|
566
589
|
return; // Prevent duplicate cleanup
|
|
567
590
|
isExiting = true;
|
|
591
|
+
clearPromptTimer(globalState);
|
|
592
|
+
if (streaming.stopWait)
|
|
593
|
+
streaming.stopWait();
|
|
568
594
|
console.log(`\n${boldCyan('Goodbye!')}`);
|
|
569
|
-
if (worldState)
|
|
570
|
-
if (streaming.stopWait) {
|
|
571
|
-
streaming.stopWait();
|
|
572
|
-
}
|
|
595
|
+
if (worldState)
|
|
573
596
|
cleanupWorldSubscription(worldState);
|
|
574
|
-
}
|
|
575
597
|
process.exit(0);
|
|
576
598
|
});
|
|
577
599
|
rl.on('SIGINT', () => {
|
|
578
600
|
if (isExiting)
|
|
579
601
|
return; // Prevent duplicate cleanup
|
|
580
602
|
isExiting = true;
|
|
603
|
+
clearPromptTimer(globalState);
|
|
604
|
+
if (streaming.stopWait)
|
|
605
|
+
streaming.stopWait();
|
|
581
606
|
console.log(`\n${boldCyan('Goodbye!')}`);
|
|
582
|
-
if (worldState)
|
|
583
|
-
if (streaming.stopWait) {
|
|
584
|
-
streaming.stopWait();
|
|
585
|
-
}
|
|
607
|
+
if (worldState)
|
|
586
608
|
cleanupWorldSubscription(worldState);
|
|
587
|
-
}
|
|
588
609
|
rl.close();
|
|
610
|
+
process.exit(0);
|
|
589
611
|
});
|
|
590
612
|
}
|
|
591
613
|
catch (err) {
|
|
@@ -598,6 +620,9 @@ async function runInteractiveMode(options) {
|
|
|
598
620
|
async function main() {
|
|
599
621
|
// Configure LLM providers from environment variables at startup
|
|
600
622
|
configureLLMProvidersFromEnv();
|
|
623
|
+
// Import help generator from commands.ts
|
|
624
|
+
// (import at top: import { generateHelpMessage } from './commands.js';)
|
|
625
|
+
const { generateHelpMessage } = await import('./commands.js');
|
|
601
626
|
program
|
|
602
627
|
.name('cli')
|
|
603
628
|
.description('Agent World CLI')
|
|
@@ -609,6 +634,8 @@ async function main() {
|
|
|
609
634
|
.option('-s, --server', 'Launch the server before running CLI')
|
|
610
635
|
.allowUnknownOption()
|
|
611
636
|
.allowExcessArguments()
|
|
637
|
+
.helpOption('-h, --help', 'Display help for command')
|
|
638
|
+
.addHelpText('beforeAll', () => generateHelpMessage())
|
|
612
639
|
.parse();
|
|
613
640
|
const options = program.opts();
|
|
614
641
|
// If --server is specified, launch the server first
|
|
@@ -629,8 +656,6 @@ async function main() {
|
|
|
629
656
|
// If server exits, exit CLI as well
|
|
630
657
|
process.exit(serverProcess.status || 0);
|
|
631
658
|
}
|
|
632
|
-
// Configure logger - set global level first, then CLI-specific level
|
|
633
|
-
await configureLogger(options.logLevel);
|
|
634
659
|
const args = program.args;
|
|
635
660
|
const messageFromArgs = args.length > 0 ? args.join(' ') : null;
|
|
636
661
|
const isPipelineMode = !!(options.command ||
|
package/dist/server/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import dotenv from 'dotenv';
|
|
17
17
|
dotenv.config();
|
|
18
18
|
import open from 'open';
|
|
19
|
-
import {
|
|
19
|
+
import { createCategoryLogger, LLMProvider } from '../core/index.js';
|
|
20
20
|
import { configureLLMProvider } from '../core/llm-config.js';
|
|
21
21
|
import express from 'express';
|
|
22
22
|
import cors from 'cors';
|
|
@@ -29,11 +29,8 @@ const __dirname = path.dirname(__filename);
|
|
|
29
29
|
// Configuration
|
|
30
30
|
const PORT = Number(process.env.PORT) || 0;
|
|
31
31
|
const HOST = process.env.HOST || '127.0.0.1';
|
|
32
|
-
|
|
33
|
-
// Initialize logger (now synchronous)
|
|
34
|
-
initializeLogger({ globalLevel: logLevel });
|
|
32
|
+
// Create server logger after logger auto-initialization
|
|
35
33
|
const serverLogger = createCategoryLogger('server');
|
|
36
|
-
serverLogger.debug('Server logger initialized', { logLevel });
|
|
37
34
|
// LLM provider configuration
|
|
38
35
|
function configureLLMProvidersFromEnv() {
|
|
39
36
|
const providers = [
|