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 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, initializeLogger, enableStreaming, disableStreaming } from '../core/index.js';
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
- // Initialize logger system with default configuration: all categories at 'error' level
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
- console.log(`${boldRed('● system:')} ${eventData.message}`);
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
- console.log(JSON.stringify(result, null, 2));
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
- console.log(JSON.stringify(result, null, 2));
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
- console.log(JSON.stringify(result, null, 2));
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
- console.log(`\n${boldRed('● system:')} ${eventData.message}`);
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('Type commands like:'))} ${cyan('/clear agent1')}, ${cyan('/clear all')}, ${cyan('/add MyAgent')}`);
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
- // Clear any existing timers immediately
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
- console.log(`${boldMagenta('Data:')} ${JSON.stringify(result.data, null, 2)}`);
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 (isExitCommand) {
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 ||
@@ -16,7 +16,7 @@
16
16
  import dotenv from 'dotenv';
17
17
  dotenv.config();
18
18
  import open from 'open';
19
- import { initializeLogger, createCategoryLogger, LLMProvider } from '../core/index.js';
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
- const logLevel = (process.env.LOG_LEVEL || 'error');
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 = [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-world",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "main": "index.ts",
5
5
  "type": "module",
6
6
  "workspaces": [