aia 0.8.2 → 0.8.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fd634957d83d1ea9d6a15fd9b82e5e535ea54952a16505490e49dd89aa1cd09e
4
- data.tar.gz: 3c53dddc42841b8bd8106a7b108ebc86a5b358a1784edef20a08ba58c659ab45
3
+ metadata.gz: 8e3b68ad8d2e1a8fb2d1e8ad7f914f1660be948bd591027884fac746f22bc006
4
+ data.tar.gz: 9ca5aaadda10b6f09cc559140f2d79210e93ea9c1106a41c1309e93e8eafe670
5
5
  SHA512:
6
- metadata.gz: 39e70a7f9a50fbad4885e181fbaa7497d0a0d997efcf6354212f4c433e588598dc40716acd1842fe82ee11de6f5e22d5157a9fdb7fe5e5f9bdea03d912a7179b
7
- data.tar.gz: bd7e23daeca3400394c6c0bdcb3b55eecf01fe61ee7a98441bc18a92e769e8a59953dda51800167f8a5212f5f7abc8657311d5a97df20d2b5e7338ec80279c4f
6
+ metadata.gz: 7a2002dbc191d05a8aa6c70f534049f049f8ed8721cacc6b93873f25a12deb256364ae324fd90971456a609ae0cb1cc899a5dc50a827175bc379a73c20614108
7
+ data.tar.gz: 3845d59a7f7a026f1cd60566cfc5eaf39658c7c49bc822e195c622d9e5799d2ebe76b52d26f2d1ece5093c22a7a811e6e19ab1985d8b13ad723260dcd329f47c
data/.version CHANGED
@@ -1 +1 @@
1
- 0.8.2
1
+ 0.8.4
data/README.md CHANGED
@@ -34,48 +34,47 @@ AIA leverages the [prompt_manager gem](https://github.com/madbomber/prompt_manag
34
34
 
35
35
  ## Table of Contents
36
36
 
37
- - [Installation](#installation)
38
- - [What is a Prompt ID?](#what-is-a-prompt-id)
39
- - [Embedded Parameters as Placeholders](#embedded-parameters-as-placeholders)
40
- - [Usage](#usage)
41
- - [Configuration Options](#configuration-options)
42
- - [Configuration Flexibility](#configuration-flexibility)
43
- - [Expandable Configuration](#expandable-configuration)
44
- - [Shell Integration inside of a Prompt](#shell-integration-inside-of-a-prompt)
45
- - [Dynamic Shell Commands](#dynamic-shell-commands)
46
- - [Shell Command Safety](#shell-command-safety)
47
- - [Chat Session Use](#chat-session-use)
48
- - [*E*mbedded *R*u*B*y (ERB)](#embedded-ruby-erb)
49
- - [Prompt Directives](#prompt-directives)
50
- - [Parameter and Shell Substitution in Directives](#parameter-and-shell-substitution-in-directives)
51
- - [Directive Syntax](#directive-syntax)
52
- - [AIA Specific Directive Commands](#aia-specific-directive-commands)
53
- - [//config](#config)
54
- - [//include](#include)
55
- - [//ruby](#ruby)
56
- - [//shell](#shell)
57
- - [//next](#next)
58
- - [//pipeline](#pipeline)
59
- - [Using Directives in Chat Sessions](#using-directives-in-chat-sessions)
60
- - [Prompt Sequences](#prompt-sequences)
61
- - [--next](#--next)
62
- - [--pipeline](#--pipeline)
63
- - [Best Practices ??](#best-practices-)
64
- - [Example pipeline](#example-pipeline)
65
- - [All About ROLES](#all-about-roles)
66
- - [The --roles_prefix (AIA_ROLES_PREFIX)](#the---roles_prefix-aia_roles_prefix)
67
- - [The --role Option](#the---role-option)
68
- - [Other Ways to Insert Roles into Prompts](#other-ways-to-insert-roles-into-prompts)
69
- - [External CLI Tools Used](#external-cli-tools-used)
70
- - [Shell Completion](#shell-completion)
71
- - [My Most Powerful Prompt](#my-most-powerful-prompt)
72
- - [My Configuration](#my-configuration)
73
- - [Executable Prompts](#executable-prompts)
74
- - [Development](#development)
75
- - [Contributing](#contributing)
76
- - [History of Development](#history-of-development)
77
- - [Roadmap](#roadmap)
78
- - [License](#license)
37
+ - [Table of Contents](#table-of-contents)
38
+ - [Installation](#installation)
39
+ - [What is a Prompt ID?](#what-is-a-prompt-id)
40
+ - [Configuration Options](#configuration-options)
41
+ - [Configuration Flexibility](#configuration-flexibility)
42
+ - [Expandable Configuration](#expandable-configuration)
43
+ - [Shell Integration inside of a Prompt](#shell-integration-inside-of-a-prompt)
44
+ - [Dynamic Shell Commands](#dynamic-shell-commands)
45
+ - [Shell Command Safety](#shell-command-safety)
46
+ - [Chat Session Use](#chat-session-use)
47
+ - [*E*mbedded *R*u*B*y (ERB)](#embedded-ruby-erb)
48
+ - [Prompt Directives](#prompt-directives)
49
+ - [Parameter and Shell Substitution in Directives](#parameter-and-shell-substitution-in-directives)
50
+ - [Directive Syntax](#directive-syntax)
51
+ - [AIA Specific Directive Commands](#aia-specific-directive-commands)
52
+ - [//config](#config)
53
+ - [//include](#include)
54
+ - [//ruby](#ruby)
55
+ - [//shell](#shell)
56
+ - [//next](#next)
57
+ - [//pipeline](#pipeline)
58
+ - [Using Directives in Chat Sessions](#using-directives-in-chat-sessions)
59
+ - [Prompt Sequences](#prompt-sequences)
60
+ - [--next](#--next)
61
+ - [--pipeline](#--pipeline)
62
+ - [Best Practices ??](#best-practices-)
63
+ - [Example pipeline](#example-pipeline)
64
+ - [All About ROLES](#all-about-roles)
65
+ - [The --roles\_prefix (AIA\_ROLES\_PREFIX)](#the---roles_prefix-aia_roles_prefix)
66
+ - [The --role Option](#the---role-option)
67
+ - [Other Ways to Insert Roles into Prompts](#other-ways-to-insert-roles-into-prompts)
68
+ - [External CLI Tools Used](#external-cli-tools-used)
69
+ - [Shell Completion](#shell-completion)
70
+ - [My Most Powerful Prompt](#my-most-powerful-prompt)
71
+ - [My Configuration](#my-configuration)
72
+ - [Executable Prompts](#executable-prompts)
73
+ - [Development](#development)
74
+ - [Contributing](#contributing)
75
+ - [History of Development](#history-of-development)
76
+ - [Roadmap](#roadmap)
77
+ - [License](#license)
79
78
 
80
79
  <!-- Tocer[finish]: Auto-generated, don't remove. -->
81
80
 
@@ -142,16 +141,32 @@ Tell me how to do something for a $(uname -s) platform that would rename all
142
141
  of the files in the directory $MY_DIRECTORY to have a prefix of for its filename
143
142
  that is [PREFIX] and a ${SUFFIX}
144
143
 
145
- # directives, ERB blocks and other junk can be used
146
- # anywhere in the file mixing dynamic context/instructions with
147
- # the static stuff.
144
+ <!--
145
+ directives, ERB blocks and other junk can be used
146
+ anywhere in the file mixing dynamic context/instructions with
147
+ the static stuff.
148
+ -->
149
+
150
+ ```markdown
151
+ # Header 1 -- not a comment
152
+ ## Header 2 -- not a comment
153
+ ### Header 3, etc -- not a comment
154
+
155
+ ```ruby
156
+ # this is a comment; but it stays in the prompt
157
+ puts "hello world" <!-- this is also a comment; but it gets removed -->
158
+ ```
159
+ Kewl!
160
+ ```
148
161
 
149
162
  __END__
150
163
 
151
- Block comments that are not part of the context or instructions to
152
- the LLM. Stuff that is just here ofr documentation.
164
+ Everything after the "__END__" line is not part of the context or instructions to
165
+ the LLM.
153
166
  ```
154
167
 
168
+ Comments in a prompt text file are just there to document the prompt. They are removed before the completed prompt is processed by the LLM. This reduces token counts; but, more importantly it helps you remember why you structured your prompt they way you did - if you remembered to document your prompt.
169
+
155
170
  That is just about everything including the kitchen sink that a pre-compositional parameterized prompt file can have. It can be an executable with a she-bang line and a special system prompt name `run` as shown in the example. It has line comments that use the `#` symbol. It had end of file block comments that appear after the "__END__" line. It has directive command that begin with the double slash `//` - an homage to IBM JCL. It has shell variables in both forms. It has shell commands. It has parameters that default to a regex that uses square brackets and all uppercase characeters to define the parameter name whose value is to be given in a Q&A session before the prompt is sent to the LLM for processing.
156
171
 
157
172
  AIA has the ability to define a workflow of prompt IDs with either the //next or //pipeline directives.
data/lib/aia/config.rb CHANGED
@@ -10,15 +10,17 @@ require 'toml-rb'
10
10
  require 'erb'
11
11
  require 'optparse'
12
12
 
13
-
14
13
  module AIA
15
14
  class Config
16
- DEFAULT_CONFIG = {
15
+ DEFAULT_CONFIG = OpenStruct.new({
17
16
  aia_dir: File.join(ENV['HOME'], '.aia'),
18
17
  config_file: File.join(ENV['HOME'], '.aia', 'config.yml'),
19
18
  out_file: 'temp.md',
20
19
  log_file: File.join(ENV['HOME'], '.prompts', '_prompts.log'),
21
20
  prompts_dir: File.join(ENV['HOME'], '.prompts'),
21
+ #
22
+ prompt_extname: PromptManager::Storage::FileSystemAdapter::PROMPT_EXTENSION,
23
+ #
22
24
  roles_prefix: 'roles',
23
25
  roles_dir: File.join(ENV['HOME'], '.prompts', 'roles'),
24
26
  role: '',
@@ -67,11 +69,10 @@ module AIA
67
69
 
68
70
  # Ruby libraries to require for Ruby binding
69
71
  require_libs: [],
70
- }.freeze
71
-
72
+ }).freeze
72
73
 
73
74
  def self.setup
74
- default_config = OpenStruct.new(DEFAULT_CONFIG)
75
+ default_config = DEFAULT_CONFIG.dup
75
76
  cli_config = cli_options
76
77
  envar_config = envar_options(default_config, cli_config)
77
78
 
@@ -92,6 +93,35 @@ module AIA
92
93
 
93
94
 
94
95
  def self.tailor_the_config(config)
96
+ remaining_args = config.remaining_args.dup
97
+ config.remaining_args = nil
98
+
99
+ # Is first remaining argument a prompt ID?
100
+ unless remaining_args.empty?
101
+ maybe_id = remaining_args.first
102
+ maybe_id_plus = File.join(config.prompts_dir, maybe_id + config.prompt_extname)
103
+
104
+ if AIA.bad_file?(maybe_id) && AIA.good_file?(maybe_id_plus)
105
+ config.prompt_id =remaining_args.shift
106
+ end
107
+ end
108
+
109
+ unless remaining_args.empty?
110
+ bad_files = remaining_args.reject { |filename| AIA.good_file?(filename) }
111
+ if bad_files.any?
112
+ STDERR.puts "Error: The following files do not exist: #{bad_files.join(', ')}"
113
+ exit 1
114
+ end
115
+
116
+ config.context_files = remaining_args
117
+ end
118
+
119
+ if config.prompt_id.nil? && !config.chat && !config.fuzzy
120
+ STDERR.puts "Error: A prompt ID is required unless using --chat, --fuzzy, or providing context files. Use -h or --help for help."
121
+ exit 1
122
+ end
123
+
124
+
95
125
  unless config.role.empty?
96
126
  unless config.roles_prefix.empty?
97
127
  unless config.role.start_with?(config.roles_prefix)
@@ -151,7 +181,7 @@ module AIA
151
181
  STDERR.puts "Error: A prompt ID is required unless using --chat, --fuzzy, or providing context files. Use -h or --help for help."
152
182
  exit 1
153
183
  end
154
-
184
+
155
185
  # If we're in chat mode with context files but no prompt_id, that's valid
156
186
  if config.chat && config.prompt_id.empty? && config.context_files && !config.context_files.empty?
157
187
  # This is a valid use case - no action needed
@@ -391,32 +421,13 @@ module AIA
391
421
 
392
422
  # Parse the command line arguments
393
423
  begin
394
- remaining_args = opt_parser.parse(args)
424
+ config.remaining_args = opt_parser.parse(args)
395
425
  rescue OptionParser::InvalidOption => e
396
426
  puts e.message
397
427
  puts opt_parser
398
428
  exit 1
399
429
  end
400
430
 
401
- # Handle remaining args
402
- unless remaining_args.empty?
403
- # If in chat mode and all args are existing files, treat them all as context files
404
- if config.chat && remaining_args.all? { |arg| File.exist?(arg) }
405
- config.context_files = remaining_args
406
- # If first arg is empty string and we're in chat mode, treat all args as context files
407
- elsif config.chat && remaining_args.first == ""
408
- remaining_args.shift # Remove the empty string
409
- config.context_files = remaining_args unless remaining_args.empty?
410
- else
411
- # First remaining arg is the prompt ID
412
- config.prompt_id = remaining_args.shift
413
-
414
- # Remaining args are context files
415
- config.context_files = remaining_args unless remaining_args.empty?
416
- end
417
- end
418
-
419
-
420
431
  config
421
432
  end
422
433
 
@@ -63,7 +63,7 @@ module AIA
63
63
  if EXCLUDED_METHODS.include?(method_name)
64
64
  return "Error: #{method_name} is not a valid directive: #{key}"
65
65
  elsif respond_to?(method_name, true)
66
- return send(method_name, args)
66
+ return send(method_name, args, context_manager)
67
67
  else
68
68
  return "Error: Unknown directive '#{key}'"
69
69
  end
@@ -125,8 +125,9 @@ module AIA
125
125
  end
126
126
 
127
127
  desc "Inserts the contents of a file Example: //include path/to/file"
128
- def include(args)
129
- file_path = args.shift
128
+ def include(args, context_manager=nil)
129
+ # echo takes care of envars and tilde expansion
130
+ file_path = `echo #{args.shift}`.strip
130
131
 
131
132
  if @included_files.include?(file_path)
132
133
  ""
@@ -143,7 +144,7 @@ module AIA
143
144
  alias_method :import, :include
144
145
 
145
146
  desc "Without arguments it will print a list of all config items and their values _or_ //config item (for one item's value) _or_ //config item = value (to set a value of an item)"
146
- def config(args = [])
147
+ def config(args = [], context_manager=nil)
147
148
  args = Array(args)
148
149
 
149
150
  if args.empty?
@@ -171,33 +172,42 @@ module AIA
171
172
  alias_method :cfg, :config
172
173
 
173
174
  desc "Shortcut for //config top_p _and_ //config top_p = value"
174
- def top_p(*args)
175
- send(:config, args.prepend('top_p'))
175
+ def top_p(args, context_manager=nil)
176
+ send(:config, args.prepend('top_p'), context_manager)
176
177
  end
177
178
  alias_method :topp, :top_p
178
179
 
180
+ desc "Review the current context"
181
+ def review(args, context_manager=nil)
182
+ ap context_manager.get_context
183
+ ''
184
+ end
185
+ alias_method :context, :review
186
+
179
187
  desc "Shortcut for //config model _and_ //config model = value"
180
- def model(*args)
181
- send(:config, args.prepend('model'))
188
+ def model(args, context_manager=nil)
189
+ send(:config, args.prepend('model'), context_manager)
182
190
  end
183
191
 
184
192
  desc "Shortcut for //config temperature _and_ //config temperature = value"
185
- def temperature(*args)
186
- send(:config, args.prepend('temperature'))
193
+ def temperature(args, context_manager=nil)
194
+ send(:config, args.prepend('temperature'), context_manager)
187
195
  end
188
196
  alias_method :temp, :temperature
189
197
 
190
198
  desc "Clears the conversation history (aka context) same as //config clear = true"
191
- def clear(args, context_manager)
199
+ def clear(args, context_manager=nil)
192
200
  if context_manager.nil?
193
201
  return "Error: Context manager not available for //clear directive."
194
202
  end
203
+
195
204
  context_manager.clear_context
196
- nil
205
+
206
+ ''
197
207
  end
198
208
 
199
209
  desc "Shortcut for a one line of ruby code; result is added to the context"
200
- def ruby(*args)
210
+ def ruby(args, context_manager=nil)
201
211
  ruby_code = args.join(' ')
202
212
 
203
213
  begin
@@ -211,25 +221,34 @@ module AIA
211
221
  end
212
222
  alias_method :rb, :ruby
213
223
 
224
+
225
+ desc "Executes one line of shell code; result is added to the context"
226
+ def shell(args, context_manager=nil)
227
+ shell_code = args.join(' ')
228
+
229
+ `#{shell_code}`
230
+ end
231
+ alias_method :sh, :shell
232
+
214
233
  desc "Use the system's say command to speak text //say some text"
215
- def say(*args)
234
+ def say(args, context_manager=nil)
216
235
  `say #{args.join(' ')}`
217
236
  ""
218
237
  end
219
238
 
220
239
  desc "Inserts an instruction to keep responses short and to the point."
221
- def terse(*args)
240
+ def terse(args, context_manager=nil)
222
241
  AIA::Session::TERSE_PROMPT
223
242
  end
224
243
 
225
244
  desc "Display the ASCII art AIA robot."
226
- def robot(*args)
245
+ def robot(args, context_manager=nil)
227
246
  AIA::Utility.robot
228
247
  ""
229
248
  end
230
249
 
231
250
  desc "Generates this help content"
232
- def help(*args)
251
+ def help(args=nil, context_manager=nil)
233
252
  puts
234
253
  puts "Available Directives"
235
254
  puts "===================="
data/lib/aia/session.rb CHANGED
@@ -158,55 +158,55 @@ module AIA
158
158
  @ui_presenter.display_chat_header
159
159
 
160
160
  Reline::HISTORY.clear # Keep Reline history for user input editing, separate from chat context
161
-
161
+
162
162
  # Load context files if any and not skipping
163
163
  if !skip_context_files && AIA.config.context_files && !AIA.config.context_files.empty?
164
164
  context_content = AIA.config.context_files.map do |file|
165
165
  File.read(file) rescue "Error reading file: #{file}"
166
166
  end.join("\n\n")
167
-
167
+
168
168
  if !context_content.empty?
169
169
  # Add context files content to context
170
170
  @context_manager.add_to_context(role: 'user', content: context_content)
171
-
171
+
172
172
  # Process the context
173
173
  operation_type = @chat_processor.determine_operation_type(AIA.config.model)
174
174
  @ui_presenter.display_thinking_animation
175
175
  response = @chat_processor.process_prompt(@context_manager.get_context, operation_type)
176
-
176
+
177
177
  # Add AI response to context
178
178
  @context_manager.add_to_context(role: 'assistant', content: response)
179
-
179
+
180
180
  # Output the response
181
181
  @chat_processor.output_response(response)
182
182
  @chat_processor.speak(response)
183
183
  @ui_presenter.display_separator
184
184
  end
185
185
  end
186
-
186
+
187
187
  # Check for piped input (STDIN not a TTY and has data)
188
188
  if !STDIN.tty?
189
189
  # Save the original STDIN
190
190
  orig_stdin = STDIN.dup
191
-
191
+
192
192
  # Read the piped input
193
193
  piped_input = STDIN.read.strip
194
-
194
+
195
195
  # Reopen STDIN to the terminal
196
196
  STDIN.reopen('/dev/tty')
197
-
197
+
198
198
  if !piped_input.empty?
199
199
  # Add piped input to context
200
200
  @context_manager.add_to_context(role: 'user', content: piped_input)
201
-
201
+
202
202
  # Process the piped input
203
203
  operation_type = @chat_processor.determine_operation_type(AIA.config.model)
204
204
  @ui_presenter.display_thinking_animation
205
205
  response = @chat_processor.process_prompt(@context_manager.get_context, operation_type)
206
-
206
+
207
207
  # Add AI response to context
208
208
  @context_manager.add_to_context(role: 'assistant', content: response)
209
-
209
+
210
210
  # Output the response
211
211
  @chat_processor.output_response(response)
212
212
  @chat_processor.speak(response)
@@ -217,7 +217,7 @@ module AIA
217
217
  loop do
218
218
  # Get user input
219
219
  prompt = @ui_presenter.ask_question
220
-
220
+
221
221
 
222
222
 
223
223
  break if prompt.nil? || prompt.strip.downcase == 'exit' || prompt.strip.empty?
@@ -232,7 +232,7 @@ module AIA
232
232
  directive_output = @directive_processor.process(prompt, @context_manager) # Pass context_manager
233
233
 
234
234
  # Add check for specific directives like //clear that might modify context
235
- if prompt.strip.start_with?('//clear', '#!clear:')
235
+ if prompt.strip.start_with?('//clear')
236
236
  # Context is likely cleared within directive_processor.process now
237
237
  # or add @context_manager.clear_context here if not handled internally
238
238
  @ui_presenter.display_info("Chat context cleared.")
@@ -256,10 +256,6 @@ module AIA
256
256
  # Use ContextManager to get the conversation
257
257
  conversation = @context_manager.get_context # System prompt handled internally
258
258
 
259
- # FIXME: remove this comment once verified
260
- # is conversation the same thing as the context for a chat session? YES
261
- # if so need to somehow delete it when the //clear directive is entered. - Addressed above/in DirectiveProcessor
262
-
263
259
  operation_type = @chat_processor.determine_operation_type(AIA.config.model)
264
260
  @ui_presenter.display_thinking_animation
265
261
  response = @chat_processor.process_prompt(conversation, operation_type)
data/lib/aia.rb CHANGED
@@ -45,6 +45,16 @@ module AIA
45
45
  @config.client = client
46
46
  end
47
47
 
48
+ def self.good_file?(filename)
49
+ File.exist?(filename) &&
50
+ File.readable?(filename) &&
51
+ !File.directory?(filename)
52
+ end
53
+
54
+ def self.bad_file?(filename)
55
+ !good_file?(filename)
56
+ end
57
+
48
58
  def self.build_flags
49
59
  @config.each_pair do |key, value|
50
60
  if [TrueClass, FalseClass].include?(value.class)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aia
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.2
4
+ version: 0.8.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
@@ -57,14 +57,14 @@ dependencies:
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 0.4.1
60
+ version: 0.5.2
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
- version: 0.4.1
67
+ version: 0.5.2
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: reline
70
70
  requirement: !ruby/object:Gem::Requirement