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.
- checksums.yaml +4 -4
- data/.version +1 -1
- data/CHANGELOG.md +17 -0
- data/README.md +32 -13
- data/lib/aia/chat_processor_service.rb +29 -39
- data/lib/aia/config.rb +261 -209
- data/lib/aia/context_manager.rb +7 -2
- data/lib/aia/directive_processor.rb +47 -2
- data/lib/aia/ruby_llm_adapter.rb +180 -63
- data/lib/aia/session.rb +5 -11
- data/lib/aia/utility.rb +17 -7
- data/lib/aia.rb +19 -4
- data/lib/extensions/ruby_llm/modalities.rb +26 -0
- data/lib/refinements/string.rb +16 -0
- metadata +18 -16
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
|
-
|
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
|
-
|
71
|
-
|
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
|
-
#
|
77
|
-
|
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
|
-
|
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
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
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
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
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
|
-
|
298
|
-
|
299
|
-
|
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
|
-
|
302
|
-
|
303
|
-
|
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
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
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
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
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
|
-
|
318
|
-
|
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
|
-
|
335
|
-
|
336
|
-
|
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
|
-
|
339
|
-
|
340
|
-
|
373
|
+
opts.on("-r", "--role ROLE_ID", "Role ID to prepend to prompt") do |role|
|
374
|
+
config.role = role
|
375
|
+
end
|
341
376
|
|
342
|
-
|
343
|
-
|
344
|
-
|
377
|
+
opts.on("--refresh DAYS", Integer, "Refresh models database interval in days") do |days|
|
378
|
+
config.refresh = days || 0
|
379
|
+
end
|
345
380
|
|
346
|
-
|
347
|
-
|
348
|
-
|
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
|
-
|
351
|
-
|
352
|
-
|
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
|
-
|
355
|
-
|
356
|
-
|
389
|
+
opts.on("-a", "--[no-]append", "Append to output file instead of overwriting") do |append|
|
390
|
+
config.append = append
|
391
|
+
end
|
357
392
|
|
358
|
-
|
359
|
-
|
360
|
-
|
393
|
+
opts.on("-l", "--[no-]log_file [FILE]", "Log file") do |file|
|
394
|
+
config.log_file = file
|
395
|
+
end
|
361
396
|
|
362
|
-
|
363
|
-
|
364
|
-
|
397
|
+
opts.on("--md", "--[no-]markdown", "Format with Markdown") do |md|
|
398
|
+
config.markdown = md
|
399
|
+
end
|
365
400
|
|
366
|
-
|
367
|
-
|
368
|
-
|
401
|
+
opts.on("-n", "--next PROMPT_ID", "Next prompt to process") do |next_prompt|
|
402
|
+
config.next = next_prompt
|
403
|
+
end
|
369
404
|
|
370
|
-
|
371
|
-
|
372
|
-
|
405
|
+
opts.on("--pipeline PROMPTS", "Pipeline of prompts to process") do |pipeline|
|
406
|
+
config.pipeline = pipeline.split(',')
|
407
|
+
end
|
373
408
|
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
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
|
-
|
383
|
-
|
384
|
-
|
417
|
+
opts.on("-d", "--debug", "Enable debug output") do
|
418
|
+
config.debug = $DEBUG_ME = true
|
419
|
+
end
|
385
420
|
|
386
|
-
|
387
|
-
|
388
|
-
|
421
|
+
opts.on("--no-debug", "Disable debug output") do
|
422
|
+
config.debug = $DEBUG_ME = false
|
423
|
+
end
|
389
424
|
|
390
|
-
|
391
|
-
|
392
|
-
|
425
|
+
opts.on("-v", "--verbose", "Be verbose") do
|
426
|
+
config.verbose = true
|
427
|
+
end
|
393
428
|
|
394
|
-
|
395
|
-
|
396
|
-
|
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
|
-
|
399
|
-
|
400
|
-
|
433
|
+
opts.on("--voice VOICE", "Voice to use for speech") do |voice|
|
434
|
+
config.voice = voice
|
435
|
+
end
|
401
436
|
|
402
|
-
|
403
|
-
|
404
|
-
|
437
|
+
opts.on("--sm", "--speech_model MODEL", "Speech model to use") do |model|
|
438
|
+
config.speech_model = model
|
439
|
+
end
|
405
440
|
|
406
|
-
|
407
|
-
|
408
|
-
|
441
|
+
opts.on("--tm", "--transcription_model MODEL", "Transcription model to use") do |model|
|
442
|
+
config.transcription_model = model
|
443
|
+
end
|
409
444
|
|
410
|
-
|
411
|
-
|
412
|
-
|
445
|
+
opts.on("--is", "--image_size SIZE", "Image size for image generation") do |size|
|
446
|
+
config.image_size = size
|
447
|
+
end
|
413
448
|
|
414
|
-
|
415
|
-
|
416
|
-
|
449
|
+
opts.on("--iq", "--image_quality QUALITY", "Image quality for image generation") do |quality|
|
450
|
+
config.image_quality = quality
|
451
|
+
end
|
417
452
|
|
418
|
-
|
419
|
-
|
420
|
-
|
453
|
+
opts.on("--style", "--image_style STYLE", "Style for image generation") do |style|
|
454
|
+
config.image_style = style
|
455
|
+
end
|
421
456
|
|
422
|
-
|
423
|
-
|
424
|
-
|
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
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
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
|
-
|
432
|
-
|
433
|
-
|
467
|
+
opts.on("--max_tokens TOKENS", Integer, "Maximum tokens for text generation") do |tokens|
|
468
|
+
config.max_tokens = tokens
|
469
|
+
end
|
434
470
|
|
435
|
-
|
436
|
-
|
437
|
-
|
471
|
+
opts.on("--top_p VALUE", Float, "Top-p sampling value") do |value|
|
472
|
+
config.top_p = value
|
473
|
+
end
|
438
474
|
|
439
|
-
|
440
|
-
|
441
|
-
|
475
|
+
opts.on("--frequency_penalty VALUE", Float, "Frequency penalty") do |value|
|
476
|
+
config.frequency_penalty = value
|
477
|
+
end
|
442
478
|
|
443
|
-
|
444
|
-
|
445
|
-
|
479
|
+
opts.on("--presence_penalty VALUE", Float, "Presence penalty") do |value|
|
480
|
+
config.presence_penalty = value
|
481
|
+
end
|
446
482
|
|
447
|
-
|
448
|
-
|
449
|
-
|
483
|
+
opts.on("--dump FILE", "Dump config to file") do |file|
|
484
|
+
config.dump_file = file
|
485
|
+
end
|
450
486
|
|
451
|
-
|
452
|
-
|
453
|
-
|
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
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
491
|
+
opts.on("--version", "Show version") do
|
492
|
+
puts AIA::VERSION
|
493
|
+
exit
|
494
|
+
end
|
459
495
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
496
|
+
opts.on("-h", "--help", "Prints this help") do
|
497
|
+
puts opts
|
498
|
+
exit
|
499
|
+
end
|
464
500
|
|
465
|
-
|
466
|
-
|
467
|
-
|
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
|
-
|
470
|
-
|
506
|
+
opts.on("--tools PATH_LIST", "Add a tool(s)") do |a_path_list|
|
507
|
+
config.tool_paths ||= []
|
471
508
|
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
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
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
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
|
-
|
489
|
-
|
490
|
-
|
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
|
-
|
499
|
-
|
535
|
+
config.tool_paths.uniq!
|
536
|
+
end
|
500
537
|
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
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
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
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
|
590
|
-
config_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)
|
data/lib/aia/context_manager.rb
CHANGED
@@ -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
|
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
|
-
|
65
|
+
STDERR.puts "ERROR: context_manager clear_context error #{e.message}"
|
61
66
|
end
|
62
67
|
end
|
63
68
|
|