aia 0.9.2 → 0.9.4

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.
data/lib/aia/config.rb CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  require 'yaml'
9
9
  require 'toml-rb'
10
+ require 'date'
10
11
  require 'erb'
11
12
  require 'optparse'
12
13
  require 'json'
@@ -16,17 +17,22 @@ require 'fileutils'
16
17
  module AIA
17
18
  class Config
18
19
  DEFAULT_CONFIG = OpenStruct.new({
20
+ adapter: 'ruby_llm', # 'ruby_llm' or ???
21
+ #
19
22
  aia_dir: File.join(ENV['HOME'], '.aia'),
20
23
  config_file: File.join(ENV['HOME'], '.aia', 'config.yml'),
21
24
  out_file: 'temp.md',
22
25
  log_file: File.join(ENV['HOME'], '.prompts', '_prompts.log'),
23
- prompts_dir: File.join(ENV['HOME'], '.prompts'),
26
+ context_files: [],
24
27
  #
28
+ prompts_dir: File.join(ENV['HOME'], '.prompts'),
25
29
  prompt_extname: PromptManager::Storage::FileSystemAdapter::PROMPT_EXTENSION,
26
30
  #
27
31
  roles_prefix: 'roles',
28
32
  roles_dir: File.join(ENV['HOME'], '.prompts', 'roles'),
29
33
  role: '',
34
+
35
+ #
30
36
  system_prompt: '',
31
37
 
32
38
  # Tools
@@ -52,7 +58,6 @@ module AIA
52
58
  pipeline: [],
53
59
 
54
60
  # PromptManager::Prompt Tailoring
55
-
56
61
  parameter_regex: PromptManager::Prompt.parameter_regex.to_s,
57
62
 
58
63
  # LLM tuning parameters
@@ -61,20 +66,26 @@ module AIA
61
66
  top_p: 1.0,
62
67
  frequency_penalty: 0.0,
63
68
  presence_penalty: 0.0,
69
+
70
+ # Audio Parameters
71
+ voice: 'alloy',
72
+ speak_command: 'afplay', # 'afplay' for audio files on MacOS
73
+
74
+ # Image Parameters
64
75
  image_size: '1024x1024',
65
76
  image_quality: 'standard',
66
77
  image_style: 'vivid',
78
+
79
+ # Models
67
80
  model: 'gpt-4o-mini',
68
81
  speech_model: 'tts-1',
69
82
  transcription_model: 'whisper-1',
70
- voice: 'alloy',
71
- adapter: 'ruby_llm', # 'ruby_llm' or ???
72
-
73
- # Embedding parameters
74
- embedding_model: 'text-embedding-ada-002',
83
+ embedding_model: 'text-embedding-ada-002',
84
+ image_model: 'dall-e-3',
75
85
 
76
- # Default speak command
77
- speak_command: 'afplay', # 'afplay' for audio files
86
+ # Model Regristery
87
+ refresh: 7, # days between refreshes of model info; 0 means every startup
88
+ last_refresh: Date.today - 1,
78
89
 
79
90
  # Ruby libraries to require for Ruby binding
80
91
  require_libs: [],
@@ -98,8 +109,13 @@ module AIA
98
109
  )
99
110
 
100
111
  tailor_the_config(config)
112
+ load_libraries(config)
101
113
  load_tools(config)
102
114
 
115
+ if config.dump_file
116
+ dump_config(config, config.dump_file)
117
+ end
118
+
103
119
  config
104
120
  end
105
121
 
@@ -180,11 +196,6 @@ module AIA
180
196
  and_exit = true
181
197
  end
182
198
 
183
- if config.dump_file
184
- dump_config(config, config.dump_file)
185
- and_exit = true
186
- end
187
-
188
199
  exit if and_exit
189
200
 
190
201
  # Only require a prompt_id if we're not in chat mode, not using fuzzy search, and no context files
@@ -207,6 +218,26 @@ module AIA
207
218
  end
208
219
 
209
220
 
221
+ def self.load_libraries(config)
222
+ return if config.require_libs.empty?
223
+
224
+ exit_on_error = false
225
+
226
+ config.require_libs.each do |library|
227
+ begin
228
+ require(library)
229
+ rescue => e
230
+ STDERR.puts "Error loading library '#{library}' #{e.message}"
231
+ exit_on_error = true
232
+ end
233
+ end
234
+
235
+ exit(1) if exit_on_error
236
+
237
+ config
238
+ end
239
+
240
+
210
241
  def self.load_tools(config)
211
242
  return if config.tool_paths.empty?
212
243
 
@@ -230,7 +261,7 @@ module AIA
230
261
  absolute_tool_path = File.expand_path(tool_path)
231
262
  require(absolute_tool_path)
232
263
  rescue => e
233
- SYSERR.puts "Error loading tool '#{tool_path}' #{e.message}"
264
+ STDERR.puts "Error loading tool '#{tool_path}' #{e.message}"
234
265
  exit_on_error = true
235
266
  end
236
267
  end
@@ -272,253 +303,265 @@ module AIA
272
303
  def self.cli_options
273
304
  config = OpenStruct.new
274
305
 
275
- opt_parser = OptionParser.new do |opts|
276
- opts.banner = "Usage: aia [options] [PROMPT_ID] [CONTEXT_FILE]*\n" +
277
- " aia --chat [PROMPT_ID] [CONTEXT_FILE]*\n" +
278
- " aia --chat [CONTEXT_FILE]*"
279
-
280
- opts.on("--chat", "Begin a chat session with the LLM after the initial prompt response; will set --no-out_file so that the LLM response comes to STDOUT.") do
281
- config.chat = true
282
- puts "Debug: Setting chat mode to true" if config.debug
283
- end
306
+ begin
307
+ opt_parser = OptionParser.new do |opts|
308
+ opts.banner = "Usage: aia [options] [PROMPT_ID] [CONTEXT_FILE]*\n" +
309
+ " aia --chat [PROMPT_ID] [CONTEXT_FILE]*\n" +
310
+ " aia --chat [CONTEXT_FILE]*"
311
+
312
+ opts.on("--chat", "Begin a chat session with the LLM after the initial prompt response; will set --no-out_file so that the LLM response comes to STDOUT.") do
313
+ config.chat = true
314
+ puts "Debug: Setting chat mode to true" if config.debug
315
+ end
284
316
 
285
- opts.on("--adapter ADAPTER", "Interface that adapts AIA to the LLM") do |adapter|
286
- adapter.downcase!
287
- valid_adapters = %w[ ruby_llm ] # NOTE: Add additional adapters here when needed
288
- if valid_adapters.include? adapter
289
- config.adapter = adapter
290
- else
291
- STDERR.puts "ERROR: Invalid adapter #{adapter} must be one of these: #{valid_adapters.join(', ')}"
292
- exit 1
317
+ opts.on("--adapter ADAPTER", "Interface that adapts AIA to the LLM") do |adapter|
318
+ adapter.downcase!
319
+ valid_adapters = %w[ ruby_llm ] # NOTE: Add additional adapters here when needed
320
+ if valid_adapters.include? adapter
321
+ config.adapter = adapter
322
+ else
323
+ STDERR.puts "ERROR: Invalid adapter #{adapter} must be one of these: #{valid_adapters.join(', ')}"
324
+ exit 1
325
+ end
293
326
  end
294
- end
295
327
 
328
+ opts.on("-m MODEL", "--model MODEL", "Name of the LLM model to use") do |model|
329
+ config.model = model
330
+ end
296
331
 
297
- opts.on("-m MODEL", "--model MODEL", "Name of the LLM model to use") do |model|
298
- config.model = model
299
- end
332
+ opts.on("--terse", "Adds a special instruction to the prompt asking the AI to keep responses short and to the point") do
333
+ config.terse = true
334
+ end
300
335
 
301
- opts.on("--terse", "Adds a special instruction to the prompt asking the AI to keep responses short and to the point") do
302
- config.terse = true
303
- end
336
+ opts.on("-c", "--config_file FILE", "Load config file") do |file|
337
+ if File.exist?(file)
338
+ ext = File.extname(file).downcase
339
+ content = File.read(file)
304
340
 
305
- opts.on("-c", "--config_file FILE", "Load config file") do |file|
306
- if File.exist?(file)
307
- ext = File.extname(file).downcase
308
- content = File.read(file)
341
+ # Process ERB if filename ends with .erb
342
+ if file.end_with?('.erb')
343
+ content = ERB.new(content).result
344
+ file = file.chomp('.erb')
345
+ File.write(file, content)
346
+ end
309
347
 
310
- # Process ERB if filename ends with .erb
311
- if file.end_with?('.erb')
312
- content = ERB.new(content).result
313
- file = file.chomp('.erb')
314
- File.write(file, content)
348
+ file_config = case ext
349
+ when '.yml', '.yaml'
350
+ YAML.safe_load(content, permitted_classes: [Symbol], symbolize_names: true)
351
+ when '.toml'
352
+ TomlRB.parse(content)
353
+ else
354
+ raise "Unsupported config file format: #{ext}"
355
+ end
356
+
357
+ file_config.each do |key, value|
358
+ config[key.to_sym] = value
359
+ end
360
+ else
361
+ raise "Config file not found: #{file}"
315
362
  end
363
+ end
316
364
 
317
- file_config = case ext
318
- when '.yml', '.yaml'
319
- YAML.safe_load(content, permitted_classes: [Symbol], symbolize_names: true)
320
- when '.toml'
321
- TomlRB.parse(content)
322
- else
323
- raise "Unsupported config file format: #{ext}"
324
- end
325
-
326
- file_config.each do |key, value|
327
- config[key.to_sym] = value
328
- end
329
- else
330
- raise "Config file not found: #{file}"
365
+ opts.on("-p", "--prompts_dir DIR", "Directory containing prompt files") do |dir|
366
+ config.prompts_dir = dir
331
367
  end
332
- end
333
368
 
334
- opts.on("-p", "--prompts_dir DIR", "Directory containing prompt files") do |dir|
335
- config.prompts_dir = dir
336
- end
369
+ opts.on("--roles_prefix PREFIX", "Subdirectory name for role files (default: roles)") do |prefix|
370
+ config.roles_prefix = prefix
371
+ end
337
372
 
338
- opts.on("--roles_prefix PREFIX", "Subdirectory name for role files (default: roles)") do |prefix|
339
- config.roles_prefix = prefix
340
- end
373
+ opts.on("-r", "--role ROLE_ID", "Role ID to prepend to prompt") do |role|
374
+ config.role = role
375
+ end
341
376
 
342
- opts.on("-r", "--role ROLE_ID", "Role ID to prepend to prompt") do |role|
343
- config.role = role
344
- end
377
+ opts.on("--refresh DAYS", Integer, "Refresh models database interval in days") do |days|
378
+ config.refresh = days || 0
379
+ end
345
380
 
346
- opts.on('--regex pattern', 'Regex pattern to extract parameters from prompt text') do |pattern|
347
- config.parameter_regex = pattern
348
- end
381
+ opts.on('--regex pattern', 'Regex pattern to extract parameters from prompt text') do |pattern|
382
+ config.parameter_regex = pattern
383
+ end
349
384
 
350
- opts.on("-o", "--[no-]out_file [FILE]", "Output file (default: temp.md)") do |file|
351
- config.out_file = file ? File.expand_path(file, Dir.pwd) : 'temp.md'
352
- end
385
+ opts.on("-o", "--[no-]out_file [FILE]", "Output file (default: temp.md)") do |file|
386
+ config.out_file = file ? File.expand_path(file, Dir.pwd) : 'temp.md'
387
+ end
353
388
 
354
- opts.on("-a", "--[no-]append", "Append to output file instead of overwriting") do |append|
355
- config.append = append
356
- end
389
+ opts.on("-a", "--[no-]append", "Append to output file instead of overwriting") do |append|
390
+ config.append = append
391
+ end
357
392
 
358
- opts.on("-l", "--[no-]log_file [FILE]", "Log file") do |file|
359
- config.log_file = file
360
- end
393
+ opts.on("-l", "--[no-]log_file [FILE]", "Log file") do |file|
394
+ config.log_file = file
395
+ end
361
396
 
362
- opts.on("--md", "--[no-]markdown", "Format with Markdown") do |md|
363
- config.markdown = md
364
- end
397
+ opts.on("--md", "--[no-]markdown", "Format with Markdown") do |md|
398
+ config.markdown = md
399
+ end
365
400
 
366
- opts.on("-n", "--next PROMPT_ID", "Next prompt to process") do |next_prompt|
367
- config.next = next_prompt
368
- end
401
+ opts.on("-n", "--next PROMPT_ID", "Next prompt to process") do |next_prompt|
402
+ config.next = next_prompt
403
+ end
369
404
 
370
- opts.on("--pipeline PROMPTS", "Pipeline of prompts to process") do |pipeline|
371
- config.pipeline = pipeline.split(',')
372
- end
405
+ opts.on("--pipeline PROMPTS", "Pipeline of prompts to process") do |pipeline|
406
+ config.pipeline = pipeline.split(',')
407
+ end
373
408
 
374
- opts.on("-f", "--fuzzy", "Use fuzzy matching for prompt search") do
375
- unless system("which fzf > /dev/null 2>&1")
376
- STDERR.puts "Error: 'fzf' is not installed. Please install 'fzf' to use the --fuzzy option."
377
- exit 1
409
+ opts.on("-f", "--fuzzy", "Use fuzzy matching for prompt search") do
410
+ unless system("which fzf > /dev/null 2>&1")
411
+ STDERR.puts "Error: 'fzf' is not installed. Please install 'fzf' to use the --fuzzy option."
412
+ exit 1
413
+ end
414
+ config.fuzzy = true
378
415
  end
379
- config.fuzzy = true
380
- end
381
416
 
382
- opts.on("-d", "--debug", "Enable debug output") do
383
- config.debug = $DEBUG_ME = true
384
- end
417
+ opts.on("-d", "--debug", "Enable debug output") do
418
+ config.debug = $DEBUG_ME = true
419
+ end
385
420
 
386
- opts.on("--no-debug", "Disable debug output") do
387
- config.debug = $DEBUG_ME = false
388
- end
421
+ opts.on("--no-debug", "Disable debug output") do
422
+ config.debug = $DEBUG_ME = false
423
+ end
389
424
 
390
- opts.on("-v", "--verbose", "Be verbose") do
391
- config.verbose = true
392
- end
425
+ opts.on("-v", "--verbose", "Be verbose") do
426
+ config.verbose = true
427
+ end
393
428
 
394
- opts.on("--speak", "Simple implementation. Uses the speech model to convert text to audio, then plays the audio. Fun with --chat. Supports configuration of speech model and voice.") do
395
- config.speak = true
396
- end
429
+ opts.on("--speak", "Simple implementation. Uses the speech model to convert text to audio, then plays the audio. Fun with --chat. Supports configuration of speech model and voice.") do
430
+ config.speak = true
431
+ end
397
432
 
398
- opts.on("--voice VOICE", "Voice to use for speech") do |voice|
399
- config.voice = voice
400
- end
433
+ opts.on("--voice VOICE", "Voice to use for speech") do |voice|
434
+ config.voice = voice
435
+ end
401
436
 
402
- opts.on("--sm", "--speech_model MODEL", "Speech model to use") do |model|
403
- config.speech_model = model
404
- end
437
+ opts.on("--sm", "--speech_model MODEL", "Speech model to use") do |model|
438
+ config.speech_model = model
439
+ end
405
440
 
406
- opts.on("--tm", "--transcription_model MODEL", "Transcription model to use") do |model|
407
- config.transcription_model = model
408
- end
441
+ opts.on("--tm", "--transcription_model MODEL", "Transcription model to use") do |model|
442
+ config.transcription_model = model
443
+ end
409
444
 
410
- opts.on("--is", "--image_size SIZE", "Image size for image generation") do |size|
411
- config.image_size = size
412
- end
445
+ opts.on("--is", "--image_size SIZE", "Image size for image generation") do |size|
446
+ config.image_size = size
447
+ end
413
448
 
414
- opts.on("--iq", "--image_quality QUALITY", "Image quality for image generation") do |quality|
415
- config.image_quality = quality
416
- end
449
+ opts.on("--iq", "--image_quality QUALITY", "Image quality for image generation") do |quality|
450
+ config.image_quality = quality
451
+ end
417
452
 
418
- opts.on("--style", "--image_style STYLE", "Style for image generation") do |style|
419
- config.image_style = style
420
- end
453
+ opts.on("--style", "--image_style STYLE", "Style for image generation") do |style|
454
+ config.image_style = style
455
+ end
421
456
 
422
- opts.on("--system_prompt PROMPT_ID", "System prompt ID to use for chat sessions") do |prompt_id|
423
- config.system_prompt = prompt_id
424
- end
457
+ opts.on("--system_prompt PROMPT_ID", "System prompt ID to use for chat sessions") do |prompt_id|
458
+ config.system_prompt = prompt_id
459
+ end
425
460
 
426
- # AI model parameters
427
- opts.on("-t", "--temperature TEMP", Float, "Temperature for text generation") do |temp|
428
- config.temperature = temp
429
- end
461
+ ###################################################
462
+ # AI model parameters
463
+ opts.on("-t", "--temperature TEMP", Float, "Temperature for text generation") do |temp|
464
+ config.temperature = temp
465
+ end
430
466
 
431
- opts.on("--max_tokens TOKENS", Integer, "Maximum tokens for text generation") do |tokens|
432
- config.max_tokens = tokens
433
- end
467
+ opts.on("--max_tokens TOKENS", Integer, "Maximum tokens for text generation") do |tokens|
468
+ config.max_tokens = tokens
469
+ end
434
470
 
435
- opts.on("--top_p VALUE", Float, "Top-p sampling value") do |value|
436
- config.top_p = value
437
- end
471
+ opts.on("--top_p VALUE", Float, "Top-p sampling value") do |value|
472
+ config.top_p = value
473
+ end
438
474
 
439
- opts.on("--frequency_penalty VALUE", Float, "Frequency penalty") do |value|
440
- config.frequency_penalty = value
441
- end
475
+ opts.on("--frequency_penalty VALUE", Float, "Frequency penalty") do |value|
476
+ config.frequency_penalty = value
477
+ end
442
478
 
443
- opts.on("--presence_penalty VALUE", Float, "Presence penalty") do |value|
444
- config.presence_penalty = value
445
- end
479
+ opts.on("--presence_penalty VALUE", Float, "Presence penalty") do |value|
480
+ config.presence_penalty = value
481
+ end
446
482
 
447
- opts.on("--dump FILE", "Dump config to file") do |file|
448
- config.dump_file = file
449
- end
483
+ opts.on("--dump FILE", "Dump config to file") do |file|
484
+ config.dump_file = file
485
+ end
450
486
 
451
- opts.on("--completion SHELL", "Show completion script for bash|zsh|fish - default is nil") do |shell|
452
- config.completion = shell
453
- end
487
+ opts.on("--completion SHELL", "Show completion script for bash|zsh|fish - default is nil") do |shell|
488
+ config.completion = shell
489
+ end
454
490
 
455
- opts.on("--version", "Show version") do
456
- puts AIA::VERSION
457
- exit
458
- end
491
+ opts.on("--version", "Show version") do
492
+ puts AIA::VERSION
493
+ exit
494
+ end
459
495
 
460
- opts.on("-h", "--help", "Prints this help") do
461
- puts opts
462
- exit
463
- end
496
+ opts.on("-h", "--help", "Prints this help") do
497
+ puts opts
498
+ exit
499
+ end
464
500
 
465
- opts.on("--rq LIBS", "Ruby libraries to require for Ruby directive") do |libs|
466
- config.require_libs = libs.split(',')
467
- end
501
+ opts.on("--rq LIBS", "--require LIBS", "Ruby libraries to require for Ruby directive") do |libs|
502
+ config.require_libs ||= []
503
+ config.require_libs += libs.split(',')
504
+ end
468
505
 
469
- opts.on("--tools PATH_LIST", "Add a tool(s)") do |a_path_list|
470
- config.tool_paths ||= []
506
+ opts.on("--tools PATH_LIST", "Add a tool(s)") do |a_path_list|
507
+ config.tool_paths ||= []
471
508
 
472
- if a_path_list.empty?
473
- STDERR.puts "No list of paths for --tools option"
474
- exit 1
475
- else
476
- paths = a_path_list.split(',').map(&:strip).uniq
477
- end
509
+ if a_path_list.empty?
510
+ STDERR.puts "No list of paths for --tools option"
511
+ exit 1
512
+ else
513
+ paths = a_path_list.split(',').map(&:strip).uniq
514
+ end
478
515
 
479
- paths.each do |a_path|
480
- if File.exist?(a_path)
481
- if File.file?(a_path)
482
- if '.rb' == File.extname(a_path)
483
- config.tool_paths << a_path
484
- else
485
- STDERR.puts "file should have *.rb extension: #{a_path}"
486
- exit 1
516
+ paths.each do |a_path|
517
+ if File.exist?(a_path)
518
+ if File.file?(a_path)
519
+ if '.rb' == File.extname(a_path)
520
+ config.tool_paths << a_path
521
+ else
522
+ STDERR.puts "file should have *.rb extension: #{a_path}"
523
+ exit 1
524
+ end
525
+ elsif File.directory?(a_path)
526
+ rb_files = Dir.glob(File.join(a_path, '**', '*.rb'))
527
+ config.tool_paths += rb_files
487
528
  end
488
- elsif File.directory?(a_path)
489
- rb_files = Dir.glob(File.join(a_path, '**', '*.rb'))
490
- config.tool_paths += rb_files
529
+ else
530
+ STDERR.puts "file/dir path is not valid: #{a_path}"
531
+ exit 1
491
532
  end
492
- else
493
- STDERR.puts "file/dir path is not valid: #{a_path}"
494
- exit 1
495
533
  end
496
- end
497
534
 
498
- config.tool_paths.uniq!
499
- end
535
+ config.tool_paths.uniq!
536
+ end
500
537
 
501
- opts.on("--at", "--allowed_tools TOOLS_LIST", "Allow only these tools to be used") do |tools_list|
502
- config.allowed_tools ||= []
503
- if tools_list.empty?
504
- STDERR.puts "No list of tool names provided for --allowed_tools option"
505
- exit 1
506
- else
507
- config.allowed_tools += tools_list.split(',').map(&:strip)
508
- config.allowed_tools.uniq!
538
+ opts.on("--at", "--allowed_tools TOOLS_LIST", "Allow only these tools to be used") do |tools_list|
539
+ config.allowed_tools ||= []
540
+ if tools_list.empty?
541
+ STDERR.puts "No list of tool names provided for --allowed_tools option"
542
+ exit 1
543
+ else
544
+ config.allowed_tools += tools_list.split(',').map(&:strip)
545
+ config.allowed_tools.uniq!
546
+ end
509
547
  end
510
- end
511
548
 
512
- opts.on("--rt", "--rejected_tools TOOLS_LIST", "Reject these tools") do |tools_list|
513
- config.rejected_tools ||= []
514
- if tools_list.empty?
515
- STDERR.puts "No list of tool names provided for --rejected_tools option"
516
- exit 1
517
- else
518
- config.rejected_tools += tools_list.split(',').map(&:strip)
519
- config.rejected_tools.uniq!
549
+ opts.on("--rt", "--rejected_tools TOOLS_LIST", "Reject these tools") do |tools_list|
550
+ config.rejected_tools ||= []
551
+ if tools_list.empty?
552
+ STDERR.puts "No list of tool names provided for --rejected_tools option"
553
+ exit 1
554
+ else
555
+ config.rejected_tools += tools_list.split(',').map(&:strip)
556
+ config.rejected_tools.uniq!
557
+ end
520
558
  end
521
559
  end
560
+ opt_parser.parse!
561
+ rescue => e
562
+ STDERR.puts "ERROR: #{e.message}"
563
+ STDERR.puts " use --help for usage report"
564
+ exit 1
522
565
  end
523
566
 
524
567
  args = ARGV.dup
@@ -566,6 +609,12 @@ module AIA
566
609
  STDERR.puts "WARNING:Config file not found: #{file}"
567
610
  end
568
611
 
612
+ if config.last_refresh
613
+ if config.last_refresh.is_a? String
614
+ config.last_refresh = Date.strptime(config.last_refresh, '%Y-%m-%d')
615
+ end
616
+ end
617
+
569
618
  config
570
619
  end
571
620
 
@@ -584,10 +633,13 @@ module AIA
584
633
  def self.dump_config(config, file)
585
634
  # Implementation for config dump
586
635
  ext = File.extname(file).downcase
636
+
637
+ config.last_refresh = config.last_refresh.to_s if config.last_refresh.is_a? Date
638
+
587
639
  config_hash = config.to_h
588
640
 
589
- # Remove non-serializable objects
590
- config_hash.delete_if { |_, v| !v.nil? && !v.is_a?(String) && !v.is_a?(Numeric) && !v.is_a?(TrueClass) && !v.is_a?(FalseClass) && !v.is_a?(Array) && !v.is_a?(Hash) }
641
+ # Remove prompt_id to prevent automatic initial pompting in --chat mode
642
+ config_hash.delete(:prompt_id)
591
643
 
592
644
  # Remove dump_file key to prevent automatic exit on next load
593
645
  config_hash.delete(:dump_file)
@@ -27,7 +27,12 @@ module AIA
27
27
  # @return [Array<Hash>] The conversation context array.
28
28
  def get_context(system_prompt: nil)
29
29
  # Ensure system prompt is present if provided and not already the first message
30
- if system_prompt && !system_prompt.strip.empty? && (@context.empty? || @context.first[:role] != 'system')
30
+ if system_prompt &&
31
+ !system_prompt.strip.empty? &&
32
+ (
33
+ @context.empty? ||
34
+ @context.first[:role] != 'system'
35
+ )
31
36
  add_system_prompt(system_prompt)
32
37
  end
33
38
  @context
@@ -57,7 +62,7 @@ module AIA
57
62
  RubyLLM.chat.clear_history
58
63
  end
59
64
  rescue => e
60
- SYSERR.puts "ERROR: context_manager clear_context error #{e.message}"
65
+ STDERR.puts "ERROR: context_manager clear_context error #{e.message}"
61
66
  end
62
67
  end
63
68