nlos 1.7.0 → 1.8.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.
Files changed (2) hide show
  1. package/bin/nlos.js +132 -4
  2. package/package.json +1 -1
package/bin/nlos.js CHANGED
@@ -319,14 +319,26 @@ function boot(options = {}) {
319
319
 
320
320
  function chat(options = {}) {
321
321
  const {
322
- model = 'qwen2.5:3b',
322
+ model = null, // null means check config
323
323
  full = false,
324
324
  minimal = false,
325
325
  profile = null,
326
326
  } = options;
327
327
 
328
- // Resolve model based on profile
329
- let selectedModel = model;
328
+ // Resolve model: CLI flag > config file > profile > default
329
+ let selectedModel = 'qwen2.5:3b';
330
+
331
+ // Check .nlos.yaml for default
332
+ const configPath = path.join(process.cwd(), '.nlos.yaml');
333
+ if (fs.existsSync(configPath)) {
334
+ const config = fs.readFileSync(configPath, 'utf-8');
335
+ const match = config.match(/default_model:\s*(\S+)/);
336
+ if (match) {
337
+ selectedModel = match[1];
338
+ }
339
+ }
340
+
341
+ // Profile overrides config
330
342
  if (profile) {
331
343
  const profiles = {
332
344
  speed: 'qwen2.5:3b',
@@ -334,7 +346,12 @@ function chat(options = {}) {
334
346
  quality: 'llama3.1:8b',
335
347
  memory_constrained: 'qwen2.5:3b',
336
348
  };
337
- selectedModel = profiles[profile] || model;
349
+ selectedModel = profiles[profile] || selectedModel;
350
+ }
351
+
352
+ // CLI flag overrides everything
353
+ if (model) {
354
+ selectedModel = model;
338
355
  }
339
356
 
340
357
  log('blue', `Starting NL-OS chat session...`);
@@ -477,6 +494,112 @@ function payload(options = {}) {
477
494
  }
478
495
  }
479
496
 
497
+ function model(args = []) {
498
+ const subcommand = args[0];
499
+ const modelName = args[1];
500
+
501
+ const configPath = path.join(process.cwd(), '.nlos.yaml');
502
+ const hasLocalConfig = fs.existsSync(configPath);
503
+
504
+ // Recommended models by capability
505
+ const recommended = {
506
+ 'qwen2.5:3b': { size: '1.9GB', context: '32K', note: 'Fast, minimal capability' },
507
+ 'qwen2.5:7b': { size: '4.4GB', context: '32K', note: 'Good balance' },
508
+ 'llama3.1:8b': { size: '4.7GB', context: '128K', note: 'Strong reasoning' },
509
+ 'mistral:7b': { size: '4.1GB', context: '32K', note: 'Fast, good quality' },
510
+ 'llama3.2:3b': { size: '2.0GB', context: '128K', note: 'Newest small model' },
511
+ 'deepseek-r1:8b': { size: '4.9GB', context: '64K', note: 'Strong reasoning' },
512
+ };
513
+
514
+ if (!subcommand || subcommand === 'list') {
515
+ log('blue', 'Recommended models for NL-OS:\n');
516
+ console.log(`${'Model'.padEnd(20)} ${'Size'.padEnd(10)} ${'Context'.padEnd(10)} Note`);
517
+ console.log('─'.repeat(60));
518
+ for (const [name, info] of Object.entries(recommended)) {
519
+ console.log(`${name.padEnd(20)} ${info.size.padEnd(10)} ${info.context.padEnd(10)} ${info.note}`);
520
+ }
521
+ console.log();
522
+ log('yellow', 'Commands:');
523
+ console.log(' nlos model use <name> Set as default and pull if needed');
524
+ console.log(' nlos model pull <name> Just pull the model');
525
+ console.log(' nlos model current Show current default');
526
+ return;
527
+ }
528
+
529
+ if (subcommand === 'current') {
530
+ if (hasLocalConfig) {
531
+ const config = fs.readFileSync(configPath, 'utf-8');
532
+ const match = config.match(/default_model:\s*(\S+)/);
533
+ if (match) {
534
+ log('green', `Current model: ${match[1]}`);
535
+ } else {
536
+ log('yellow', 'No default model set. Using: qwen2.5:3b');
537
+ }
538
+ } else {
539
+ log('yellow', 'No .nlos.yaml found. Run "nlos init" first, or using default: qwen2.5:3b');
540
+ }
541
+ return;
542
+ }
543
+
544
+ if (subcommand === 'pull') {
545
+ if (!modelName) {
546
+ log('red', 'Usage: nlos model pull <name>');
547
+ return;
548
+ }
549
+ log('blue', `Pulling ${modelName}...`);
550
+ try {
551
+ execSync(`ollama pull ${modelName}`, { stdio: 'inherit' });
552
+ log('green', `\nModel ${modelName} ready!`);
553
+ } catch (error) {
554
+ log('red', `Failed to pull: ${error.message}`);
555
+ }
556
+ return;
557
+ }
558
+
559
+ if (subcommand === 'use' || subcommand === 'set') {
560
+ if (!modelName) {
561
+ log('red', 'Usage: nlos model use <name>');
562
+ return;
563
+ }
564
+
565
+ // Pull model if not present
566
+ log('blue', `Setting up ${modelName}...\n`);
567
+ try {
568
+ execSync(`ollama list | grep -q "^${modelName.split(':')[0]}"`, { stdio: 'pipe' });
569
+ log('cyan', `Model ${modelName} already pulled`);
570
+ } catch {
571
+ log('yellow', `Pulling ${modelName}...`);
572
+ try {
573
+ execSync(`ollama pull ${modelName}`, { stdio: 'inherit' });
574
+ } catch (error) {
575
+ log('red', `Failed to pull: ${error.message}`);
576
+ return;
577
+ }
578
+ }
579
+
580
+ // Update .nlos.yaml if it exists
581
+ if (hasLocalConfig) {
582
+ let config = fs.readFileSync(configPath, 'utf-8');
583
+ if (config.includes('default_model:')) {
584
+ config = config.replace(/default_model:\s*\S+/, `default_model: ${modelName}`);
585
+ } else {
586
+ config += `\nkernel:\n default_model: ${modelName}\n`;
587
+ }
588
+ fs.writeFileSync(configPath, config);
589
+ log('green', `\nDefault model set to: ${modelName}`);
590
+ console.log(`\nRun ${colors.cyan}nlos chat --minimal${colors.reset} to start`);
591
+ } else {
592
+ log('green', `\nModel ${modelName} ready!`);
593
+ console.log(`\nRun ${colors.cyan}nlos chat --minimal --model ${modelName}${colors.reset} to start`);
594
+ console.log(`Or run ${colors.cyan}nlos init${colors.reset} first to save as default`);
595
+ }
596
+ return;
597
+ }
598
+
599
+ log('red', `Unknown subcommand: ${subcommand}`);
600
+ console.log('Use: nlos model list|use|pull|current');
601
+ }
602
+
480
603
  function clean(options = {}) {
481
604
  const { local = false, all = false } = options;
482
605
 
@@ -667,6 +790,7 @@ ${colors.yellow}Usage:${colors.reset}
667
790
  ${colors.yellow}Commands:${colors.reset}
668
791
  init Initialize NL-OS workspace in current directory
669
792
  chat Interactive NL-OS chat session (recommended)
793
+ model Manage models (list, use, pull, current)
670
794
  clean Remove Ollama model and optionally local files
671
795
  boot Boot NL-OS and verify kernel loads
672
796
  payload Generate portable kernel payloads
@@ -757,6 +881,10 @@ switch (command) {
757
881
  clean(options);
758
882
  break;
759
883
 
884
+ case 'model':
885
+ model(args.slice(1));
886
+ break;
887
+
760
888
  case 'chat':
761
889
  chat(options);
762
890
  break;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nlos",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Natural Language Operating System - A model-agnostic kernel for any LLM",
5
5
  "main": "bin/nlos.js",
6
6
  "bin": {