aia 0.9.24 → 0.10.2
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 +84 -3
- data/README.md +179 -59
- data/bin/aia +6 -0
- data/docs/cli-reference.md +145 -72
- data/docs/configuration.md +156 -19
- data/docs/examples/tools/index.md +2 -2
- data/docs/faq.md +11 -11
- data/docs/guides/available-models.md +11 -11
- data/docs/guides/basic-usage.md +18 -17
- data/docs/guides/chat.md +57 -11
- data/docs/guides/executable-prompts.md +15 -15
- data/docs/guides/first-prompt.md +2 -2
- data/docs/guides/getting-started.md +6 -6
- data/docs/guides/image-generation.md +24 -24
- data/docs/guides/local-models.md +2 -2
- data/docs/guides/models.md +96 -18
- data/docs/guides/tools.md +4 -4
- data/docs/installation.md +2 -2
- data/docs/prompt_management.md +11 -11
- data/docs/security.md +3 -3
- data/docs/workflows-and-pipelines.md +1 -1
- data/examples/README.md +6 -6
- data/examples/headlines +3 -3
- data/lib/aia/aia_completion.bash +2 -2
- data/lib/aia/aia_completion.fish +4 -4
- data/lib/aia/aia_completion.zsh +2 -2
- data/lib/aia/chat_processor_service.rb +31 -21
- data/lib/aia/config/cli_parser.rb +403 -403
- data/lib/aia/config/config_section.rb +87 -0
- data/lib/aia/config/defaults.yml +219 -0
- data/lib/aia/config/defaults_loader.rb +147 -0
- data/lib/aia/config/mcp_parser.rb +151 -0
- data/lib/aia/config/model_spec.rb +67 -0
- data/lib/aia/config/validator.rb +185 -136
- data/lib/aia/config.rb +336 -17
- data/lib/aia/directive_processor.rb +14 -6
- data/lib/aia/directives/configuration.rb +24 -10
- data/lib/aia/directives/models.rb +3 -4
- data/lib/aia/directives/utility.rb +3 -2
- data/lib/aia/directives/web_and_file.rb +50 -47
- data/lib/aia/logger.rb +328 -0
- data/lib/aia/prompt_handler.rb +18 -22
- data/lib/aia/ruby_llm_adapter.rb +572 -69
- data/lib/aia/session.rb +9 -8
- data/lib/aia/ui_presenter.rb +20 -16
- data/lib/aia/utility.rb +50 -18
- data/lib/aia.rb +91 -66
- data/lib/extensions/ruby_llm/modalities.rb +2 -0
- data/mcp_servers/apple-mcp.json +8 -0
- data/mcp_servers/mcp_server_chart.json +11 -0
- data/mcp_servers/playwright_one.json +8 -0
- data/mcp_servers/playwright_two.json +8 -0
- data/mcp_servers/tavily_mcp_server.json +8 -0
- metadata +83 -25
- data/lib/aia/config/base.rb +0 -308
- data/lib/aia/config/defaults.rb +0 -91
- data/lib/aia/config/file_loader.rb +0 -163
- data/mcp_servers/imcp.json +0 -7
- data/mcp_servers/launcher.json +0 -11
- data/mcp_servers/timeserver.json +0 -8
data/lib/aia/session.rb
CHANGED
|
@@ -53,8 +53,9 @@ module AIA
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def setup_output_file
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
out_file = AIA.config.output.file
|
|
57
|
+
if out_file && !out_file.nil? && !AIA.append? && File.exist?(out_file)
|
|
58
|
+
File.open(out_file, "w") { } # Truncate the file
|
|
58
59
|
end
|
|
59
60
|
end
|
|
60
61
|
|
|
@@ -117,7 +118,7 @@ module AIA
|
|
|
117
118
|
end
|
|
118
119
|
|
|
119
120
|
def setup_prompt_processing(prompt_id)
|
|
120
|
-
role_id = AIA.config.role
|
|
121
|
+
role_id = AIA.config.prompts.role
|
|
121
122
|
|
|
122
123
|
begin
|
|
123
124
|
prompt = @prompt_handler.get_prompt(prompt_id, role_id)
|
|
@@ -351,8 +352,8 @@ module AIA
|
|
|
351
352
|
|
|
352
353
|
break if follow_up_prompt.nil? || follow_up_prompt.strip.downcase == "exit" || follow_up_prompt.strip.empty?
|
|
353
354
|
|
|
354
|
-
if AIA.config.
|
|
355
|
-
File.open(AIA.config.
|
|
355
|
+
if AIA.config.output.file
|
|
356
|
+
File.open(AIA.config.output.file, "a") do |file|
|
|
356
357
|
file.puts "\nYou: #{follow_up_prompt}"
|
|
357
358
|
end
|
|
358
359
|
end
|
|
@@ -383,8 +384,8 @@ module AIA
|
|
|
383
384
|
|
|
384
385
|
@ui_presenter.display_ai_response(content)
|
|
385
386
|
|
|
386
|
-
# Display
|
|
387
|
-
if AIA.config.
|
|
387
|
+
# Display token usage if enabled and available (chat mode only)
|
|
388
|
+
if AIA.config.flags.tokens
|
|
388
389
|
if multi_metrics
|
|
389
390
|
# Display metrics for each model in multi-model mode
|
|
390
391
|
@ui_presenter.display_multi_model_metrics(multi_metrics)
|
|
@@ -471,7 +472,7 @@ module AIA
|
|
|
471
472
|
|
|
472
473
|
def cleanup_chat_prompt
|
|
473
474
|
if @chat_prompt_id
|
|
474
|
-
|
|
475
|
+
logger.debug("Cleaning up chat prompt", chat_prompt_id: @chat_prompt_id)
|
|
475
476
|
begin
|
|
476
477
|
@chat_prompt.delete
|
|
477
478
|
@chat_prompt_id = nil # Prevent repeated attempts if error occurs elsewhere
|
data/lib/aia/ui_presenter.rb
CHANGED
|
@@ -26,8 +26,9 @@ module AIA
|
|
|
26
26
|
puts "\nAI: "
|
|
27
27
|
format_chat_response(response)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
out_file = AIA.config.output.file
|
|
30
|
+
if out_file && !out_file.nil?
|
|
31
|
+
File.open(out_file, 'a') do |file|
|
|
31
32
|
file.puts "\nAI: "
|
|
32
33
|
format_chat_response(response, file)
|
|
33
34
|
end
|
|
@@ -125,7 +126,7 @@ module AIA
|
|
|
125
126
|
output_lines << "═" * 55
|
|
126
127
|
output_lines << "Model: #{metrics[:model_id]}"
|
|
127
128
|
|
|
128
|
-
if AIA.config.
|
|
129
|
+
if AIA.config.flags.cost
|
|
129
130
|
output_lines.concat(format_metrics_with_cost(metrics))
|
|
130
131
|
else
|
|
131
132
|
output_lines.concat(format_metrics_basic(metrics))
|
|
@@ -137,20 +138,21 @@ module AIA
|
|
|
137
138
|
output_lines.each { |line| puts line }
|
|
138
139
|
|
|
139
140
|
# Also write to file if configured
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
out_file = AIA.config.output.file
|
|
142
|
+
if out_file && !out_file.nil?
|
|
143
|
+
File.open(out_file, 'a') do |file|
|
|
142
144
|
output_lines.each { |line| file.puts line }
|
|
143
145
|
end
|
|
144
146
|
end
|
|
145
147
|
end
|
|
146
|
-
|
|
148
|
+
|
|
147
149
|
def display_multi_model_metrics(metrics_list)
|
|
148
150
|
return unless metrics_list && !metrics_list.empty?
|
|
149
151
|
|
|
150
152
|
output_lines = []
|
|
151
153
|
|
|
152
154
|
# Determine table width based on whether costs are shown
|
|
153
|
-
if AIA.config.
|
|
155
|
+
if AIA.config.flags.cost
|
|
154
156
|
table_width = 80
|
|
155
157
|
else
|
|
156
158
|
table_width = 60
|
|
@@ -161,7 +163,7 @@ module AIA
|
|
|
161
163
|
output_lines << "─" * table_width
|
|
162
164
|
|
|
163
165
|
# Build header row
|
|
164
|
-
if AIA.config.
|
|
166
|
+
if AIA.config.flags.cost
|
|
165
167
|
output_lines << sprintf("%-20s %10s %10s %10s %12s %10s",
|
|
166
168
|
"Model", "Input", "Output", "Total", "Cost", "x1000")
|
|
167
169
|
output_lines << "─" * table_width
|
|
@@ -177,15 +179,16 @@ module AIA
|
|
|
177
179
|
total_cost = 0.0
|
|
178
180
|
|
|
179
181
|
metrics_list.each do |metrics|
|
|
180
|
-
|
|
182
|
+
# Use display_name if available (includes role), otherwise fall back to model_id
|
|
183
|
+
model_name = metrics[:display_name] || metrics[:model_id]
|
|
181
184
|
# Truncate model name if too long
|
|
182
|
-
model_name = model_name[0..17] + ".." if model_name.length > 19
|
|
183
|
-
|
|
185
|
+
model_name = model_name[0..17] + ".." if model_name.to_s.length > 19
|
|
186
|
+
|
|
184
187
|
input_tokens = metrics[:input_tokens] || 0
|
|
185
188
|
output_tokens = metrics[:output_tokens] || 0
|
|
186
189
|
total_tokens = input_tokens + output_tokens
|
|
187
190
|
|
|
188
|
-
if AIA.config.
|
|
191
|
+
if AIA.config.flags.cost
|
|
189
192
|
cost_data = calculate_cost(metrics)
|
|
190
193
|
if cost_data[:available]
|
|
191
194
|
cost_str = "$#{'%.5f' % cost_data[:total_cost]}"
|
|
@@ -211,7 +214,7 @@ module AIA
|
|
|
211
214
|
output_lines << "─" * table_width
|
|
212
215
|
total_tokens = total_input + total_output
|
|
213
216
|
|
|
214
|
-
if AIA.config.
|
|
217
|
+
if AIA.config.flags.cost && total_cost > 0
|
|
215
218
|
cost_str = "$#{'%.5f' % total_cost}"
|
|
216
219
|
x1000_str = "$#{'%.2f' % (total_cost * 1000)}"
|
|
217
220
|
output_lines << sprintf("%-20s %10d %10d %10d %12s %10s",
|
|
@@ -227,13 +230,14 @@ module AIA
|
|
|
227
230
|
output_lines.each { |line| puts line }
|
|
228
231
|
|
|
229
232
|
# Also write to file if configured
|
|
230
|
-
|
|
231
|
-
|
|
233
|
+
out_file = AIA.config.output.file
|
|
234
|
+
if out_file && !out_file.nil?
|
|
235
|
+
File.open(out_file, 'a') do |file|
|
|
232
236
|
output_lines.each { |line| file.puts line }
|
|
233
237
|
end
|
|
234
238
|
end
|
|
235
239
|
end
|
|
236
|
-
|
|
240
|
+
|
|
237
241
|
private
|
|
238
242
|
|
|
239
243
|
def display_metrics_basic(metrics)
|
data/lib/aia/utility.rb
CHANGED
|
@@ -10,22 +10,49 @@ module AIA
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def user_tools?
|
|
13
|
-
AIA.config&.
|
|
13
|
+
AIA.config&.tools&.paths && !AIA.config.tools.paths.empty?
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def mcp_servers?
|
|
17
17
|
AIA.config&.mcp_servers && !AIA.config.mcp_servers.empty?
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
# Returns only successfully connected MCP server names
|
|
20
21
|
def mcp_server_names
|
|
22
|
+
# Use connected_mcp_servers if available (populated during MCP setup)
|
|
23
|
+
connected = AIA.config&.connected_mcp_servers
|
|
24
|
+
return connected if connected && !connected.empty?
|
|
25
|
+
|
|
26
|
+
# Fallback to configured servers if connection status not yet known
|
|
21
27
|
return [] unless mcp_servers?
|
|
22
28
|
AIA.config.mcp_servers.map { |s| s[:name] || s["name"] }.compact
|
|
23
29
|
end
|
|
24
30
|
|
|
31
|
+
# Returns true if there are any connected MCP servers
|
|
32
|
+
def connected_mcp_servers?
|
|
33
|
+
connected = AIA.config&.connected_mcp_servers
|
|
34
|
+
connected && !connected.empty?
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Returns list of failed MCP servers with their errors
|
|
38
|
+
def failed_mcp_servers
|
|
39
|
+
AIA.config&.failed_mcp_servers || []
|
|
40
|
+
end
|
|
41
|
+
|
|
25
42
|
def supports_tools?
|
|
26
|
-
AIA.
|
|
43
|
+
AIA.client&.model&.supports_functions? || false
|
|
27
44
|
end
|
|
28
45
|
|
|
46
|
+
# Returns the last refresh date from models.json modification time
|
|
47
|
+
def models_last_refresh
|
|
48
|
+
aia_dir = AIA.config&.paths&.aia_dir
|
|
49
|
+
return nil if aia_dir.nil?
|
|
50
|
+
|
|
51
|
+
models_file = File.join(File.expand_path(aia_dir), 'models.json')
|
|
52
|
+
return nil unless File.exist?(models_file)
|
|
53
|
+
|
|
54
|
+
File.mtime(models_file).strftime('%Y-%m-%d %H:%M')
|
|
55
|
+
end
|
|
29
56
|
|
|
30
57
|
# Displays the AIA robot ASCII art
|
|
31
58
|
# Yes, its slightly frivolous but it does contain some
|
|
@@ -37,40 +64,45 @@ module AIA
|
|
|
37
64
|
|
|
38
65
|
mcp_version = defined?(RubyLLM::MCP::VERSION) ? " MCP v" + RubyLLM::MCP::VERSION : ''
|
|
39
66
|
|
|
40
|
-
# Extract model names from config (handles
|
|
41
|
-
model_display = if AIA.config&.
|
|
42
|
-
models = AIA.config.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
# Extract model names from config (handles ModelSpec objects or Hashes)
|
|
68
|
+
model_display = if AIA.config&.models && !AIA.config.models.empty?
|
|
69
|
+
models = AIA.config.models
|
|
70
|
+
models.map do |spec|
|
|
71
|
+
if spec.is_a?(AIA::ModelSpec)
|
|
72
|
+
spec.name
|
|
73
|
+
elsif spec.is_a?(Hash)
|
|
74
|
+
spec[:name] || spec['name'] || spec.to_s
|
|
48
75
|
else
|
|
49
|
-
|
|
76
|
+
spec.to_s
|
|
50
77
|
end
|
|
51
|
-
|
|
52
|
-
models.to_s
|
|
53
|
-
end
|
|
78
|
+
end.join(', ')
|
|
54
79
|
else
|
|
55
80
|
'unknown-model'
|
|
56
81
|
end
|
|
57
82
|
|
|
58
|
-
|
|
83
|
+
# Build MCP line based on connection status
|
|
84
|
+
mcp_line = if !mcp_servers?
|
|
85
|
+
'' # No MCP servers configured
|
|
86
|
+
elsif connected_mcp_servers?
|
|
87
|
+
"MCP: #{mcp_server_names.join(', ')}"
|
|
88
|
+
else
|
|
89
|
+
"MCP: (none connected)"
|
|
90
|
+
end
|
|
59
91
|
|
|
60
92
|
puts <<-ROBOT
|
|
61
93
|
|
|
62
94
|
, ,
|
|
63
95
|
(\\____/) AI Assistant (v#{AIA::VERSION}) is Online
|
|
64
96
|
(_oo_) #{model_display}#{supports_tools? ? ' (supports tools)' : ''}
|
|
65
|
-
(O) using #{AIA.config&.adapter || 'unknown-adapter'} (v#{RubyLLM::VERSION}#{mcp_version})
|
|
97
|
+
(O) using #{AIA.config&.llm&.adapter || 'unknown-adapter'} (v#{RubyLLM::VERSION}#{mcp_version})
|
|
66
98
|
__||__ \\) model db was last refreshed on
|
|
67
|
-
[/______\\] / #{
|
|
99
|
+
[/______\\] / #{models_last_refresh || 'unknown'}
|
|
68
100
|
/ \\__AI__/ \\/ #{user_tools? ? 'I will also use your tools' : (tools? ? 'You can share my tools' : 'I did not bring any tools')}
|
|
69
101
|
/ /__\\ #{mcp_line}
|
|
70
102
|
(\\ /____\\ #{user_tools? && tools? ? 'My Toolbox contains:' : ''}
|
|
71
103
|
ROBOT
|
|
72
104
|
if user_tools? && tools?
|
|
73
|
-
tool_names = AIA.config.
|
|
105
|
+
tool_names = AIA.config.tool_names
|
|
74
106
|
if tool_names && !tool_names.to_s.empty?
|
|
75
107
|
puts WordWrapper::MinimumRaggedness.new(
|
|
76
108
|
width,
|
data/lib/aia.rb
CHANGED
|
@@ -21,14 +21,20 @@ DebugMeDefaultOptions[:skip1] = true
|
|
|
21
21
|
require_relative 'extensions/openstruct_merge' # adds self.merge self.get_value
|
|
22
22
|
require_relative 'extensions/ruby_llm/modalities' # adds model.modalities.text_to_text? etc.
|
|
23
23
|
|
|
24
|
-
require_relative 'refinements/string
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
require_relative 'refinements/string' # adds #include_any? #include_all?
|
|
28
25
|
|
|
29
26
|
require_relative 'aia/utility'
|
|
30
27
|
require_relative 'aia/version'
|
|
31
28
|
require_relative 'aia/config'
|
|
29
|
+
require_relative 'aia/logger'
|
|
30
|
+
|
|
31
|
+
# Top-level logger method available anywhere in the application
|
|
32
|
+
def logger
|
|
33
|
+
AIA::LoggerManager.aia_logger
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
require_relative 'aia/config/cli_parser'
|
|
37
|
+
require_relative 'aia/config/validator'
|
|
32
38
|
require_relative 'aia/prompt_handler'
|
|
33
39
|
require_relative 'aia/ruby_llm_adapter'
|
|
34
40
|
require_relative 'aia/directive_processor'
|
|
@@ -41,86 +47,105 @@ require_relative 'aia/session'
|
|
|
41
47
|
# provides an interface for interacting with AI models and managing prompts.
|
|
42
48
|
module AIA
|
|
43
49
|
at_exit do
|
|
44
|
-
|
|
45
|
-
# Clean up temporary STDIN file if it exists
|
|
46
|
-
if @config&.stdin_temp_file && File.exist?(@config.stdin_temp_file)
|
|
47
|
-
File.unlink(@config.stdin_temp_file)
|
|
48
|
-
end
|
|
50
|
+
warn 'Exiting AIA application...'
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
@config = nil
|
|
54
|
+
@client = nil
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
end
|
|
56
|
+
class << self
|
|
57
|
+
attr_accessor :config, :client
|
|
56
58
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
def good_file?(filename)
|
|
60
|
+
File.exist?(filename) &&
|
|
61
|
+
File.readable?(filename) &&
|
|
62
|
+
!File.directory?(filename)
|
|
63
|
+
end
|
|
60
64
|
|
|
61
|
-
def self.client=(client)
|
|
62
|
-
@config.client = client
|
|
63
|
-
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
!File.directory?(filename)
|
|
69
|
-
end
|
|
66
|
+
def bad_file?(filename)
|
|
67
|
+
!good_file?(filename)
|
|
68
|
+
end
|
|
70
69
|
|
|
71
|
-
def self.bad_file?(filename)
|
|
72
|
-
!good_file?(filename)
|
|
73
|
-
end
|
|
74
70
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
define_singleton_method("#{key}?") do
|
|
79
|
-
@config[key]
|
|
80
|
-
end
|
|
81
|
-
end
|
|
71
|
+
# Convenience flag accessors (delegate to config.flags section)
|
|
72
|
+
def chat?
|
|
73
|
+
@config&.flags&.chat == true
|
|
82
74
|
end
|
|
83
|
-
end
|
|
84
75
|
|
|
85
|
-
def self.run
|
|
86
|
-
@config = Config.setup
|
|
87
76
|
|
|
88
|
-
|
|
77
|
+
def debug?
|
|
78
|
+
@config&.flags&.debug == true
|
|
79
|
+
end
|
|
89
80
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
81
|
+
|
|
82
|
+
def verbose?
|
|
83
|
+
@config&.flags&.verbose == true
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def fuzzy?
|
|
88
|
+
@config&.flags&.fuzzy == true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def terse?
|
|
93
|
+
@config&.flags&.terse == true
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def speak?
|
|
98
|
+
@config&.flags&.speak == true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def append?
|
|
103
|
+
@config&.output&.append == true
|
|
102
104
|
end
|
|
103
105
|
|
|
104
|
-
prompt_handler = PromptHandler.new
|
|
105
106
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
else
|
|
110
|
-
# TODO: ?? some other LLM API wrapper
|
|
111
|
-
STDERR.puts "ERROR: There is no adapter for #{@config.adapter}"
|
|
112
|
-
exit 1
|
|
113
|
-
end
|
|
107
|
+
def run
|
|
108
|
+
# Parse CLI arguments
|
|
109
|
+
cli_overrides = CLIParser.parse
|
|
114
110
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
# BUT its also possible to start a chat session with an initial prompt AND
|
|
118
|
-
# within that initial prompt there can be a workflow (aka pipeline)
|
|
119
|
-
# defined. If that is the case, then the chat session will not start
|
|
120
|
-
# until the initial prompt has completed its workflow.
|
|
111
|
+
# Create config with CLI overrides
|
|
112
|
+
@config = Config.setup(cli_overrides)
|
|
121
113
|
|
|
122
|
-
|
|
114
|
+
# Validate and tailor configuration (handles --dump early exit)
|
|
115
|
+
ConfigValidator.tailor(@config)
|
|
123
116
|
|
|
124
|
-
|
|
117
|
+
# Load Fzf if fuzzy search is enabled and fzf is installed
|
|
118
|
+
if @config.flags.fuzzy
|
|
119
|
+
begin
|
|
120
|
+
if system('which fzf >/dev/null 2>&1')
|
|
121
|
+
require_relative 'aia/fzf'
|
|
122
|
+
else
|
|
123
|
+
warn 'Warning: Fuzzy search enabled but fzf not found. Install fzf for enhanced search capabilities.'
|
|
124
|
+
end
|
|
125
|
+
rescue StandardError => e
|
|
126
|
+
warn "Warning: Failed to load fzf: #{e.message}"
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
prompt_handler = PromptHandler.new
|
|
131
|
+
|
|
132
|
+
# Initialize the appropriate client adapter based on configuration
|
|
133
|
+
@client = if 'ruby_llm' == @config.llm.adapter
|
|
134
|
+
RubyLLMAdapter.new
|
|
135
|
+
else
|
|
136
|
+
warn "ERROR: There is no adapter for #{@config.llm.adapter}"
|
|
137
|
+
exit 1
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# There are two kinds of sessions: batch and chat
|
|
141
|
+
# A chat session is started when the --chat CLI option is used
|
|
142
|
+
# BUT its also possible to start a chat session with an initial prompt AND
|
|
143
|
+
# within that initial prompt there can be a workflow (aka pipeline)
|
|
144
|
+
# defined. If that is the case, then the chat session will not start
|
|
145
|
+
# until the initial prompt has completed its workflow.
|
|
146
|
+
|
|
147
|
+
session = Session.new(prompt_handler)
|
|
148
|
+
session.start
|
|
149
|
+
end
|
|
125
150
|
end
|
|
126
151
|
end
|