# lib/aia/main.rb module AIA ; end require_relative 'config' require_relative 'cli' require_relative 'directives' require_relative 'dynamic_content' require_relative 'prompt' require_relative 'logging' require_relative 'tools' require_relative 'user_query' # Everything is being handled within the context # of a single class. class AIA::Main SPINNER_FORMAT = :bouncing_ball include AIA::DynamicContent include AIA::UserQuery attr_accessor :logger, :tools, :backend attr_reader :spinner def initialize(args= ARGV) AIA::Tools.load_tools AIA::Cli.new(args) if AIA.config.debug? debug_me('== CONFIG AFTER CLI =='){[ "AIA.config" ]} end @spinner = TTY::Spinner.new(":spinner :title", format: SPINNER_FORMAT) spinner.update(title: "composing response ... ") @logger = AIA::Logging.new(AIA.config.log_file) @logger.info(AIA.config) if AIA.config.debug? || AIA.config.verbose? @prompt = AIA::Prompt.new.prompt @directives_processor = AIA::Directives.new # TODO: still should verify that the tools are ion the $PATH # tools.class.verify_tools end def speak(what) return false unless AIA.config.speak? # TODO: Consider putting this into a thread # so that it can speak at the same time # the output is going to the screen # MacOS uses the say command system "say #{Shellwords.escape(what)}" true end # Function to setup the Reline history with a maximum depth def setup_reline_history(max_history_size=5) Reline::HISTORY.clear # Reline::HISTORY.max_size = max_history_size end def call @directives_processor.execute_my_directives if AIA.config.chat? AIA.config.out_file = STDOUT AIA.config.extra = "--quiet" if 'mods' == AIA.config.backend end # TODO: the context_files left in the @arguments array # should be verified BEFORE asking the user for a # prompt keyword or process the prompt. Do not # want invalid files to make it this far. found = AIA::Tools .search_for( name: AIA.config.backend, role: :backend ) if found.empty? abort "There are no :backend tools named #{AIA.config.backend}" end if found.size > 1 abort "There are #{found.size} :backend tools with the name #{AIAA.config.backend}" end backend_klass = found.first.klass abort "backend not found: #{AIA.config.backend}" if backend_klass.nil? the_prompt = @prompt.to_s if AIA.config.terse? the_prompt.prepend "Be terse in your response. " end @backend = backend_klass.new( text: the_prompt, files: AIA.config.arguments # FIXME: want validated context files ) result = get_and_display_result(the_prompt) logger.prompt_result(@prompt, result) if AIA.config.chat? setup_reline_history speak result lets_chat end end def get_and_display_result(the_prompt_text) spinner.auto_spin if AIA.config.verbose? backend.text = the_prompt_text result = backend.run if AIA.config.verbose? spinner.success "Done." end AIA.config.out_file.write "\nResponse:\n" if STDOUT == AIA.config.out_file if AIA.config.render? AIA::Glow.new(content: result).run else result = result.wrap(indent: 2) AIA.config.out_file.write result end else AIA.config.out_file.write result if AIA.config.render? AIA::Glow.new(file_path: AIA.config.out_file).run end end result end def log_the_follow_up(the_prompt_text, result) logger.info "Follow Up:\n#{the_prompt_text}" logger.info "Response:\n#{result}" end def add_continue_option if 'mods' == AIA.config.backend continue_option = " -C" AIA.config.extra += continue_option unless AIA.config.extra.include?(continue_option) end end def insert_terse_phrase(a_string) if AIA.config.terse? a_string.prepend "Be terse in your response. " end a_string end def handle_directives(the_prompt_text) signal = PromptManager::Prompt::DIRECTIVE_SIGNAL result = the_prompt_text.start_with?(signal) if result parts = the_prompt_text[signal.size..].split(' ') directive = parts.shift parameters = parts.join(' ') AIA.config.directives << [directive, parameters] @directives_processor.execute_my_directives end result end def lets_chat add_continue_option the_prompt_text = ask_question_with_reline("\nFollow Up: ") until the_prompt_text.empty? the_prompt_text = render_erb(the_prompt_text) if AIA.config.erb? the_prompt_text = render_env(the_prompt_text) if AIA.config.shell? unless handle_directives(the_prompt_text) the_prompt_text = insert_terse_phrase(the_prompt_text) result = get_and_display_result(the_prompt_text) log_the_follow_up(the_prompt_text, result) speak result end the_prompt_text = ask_question_with_reline("\nFollow Up: ") end end end