lib/boxcars/boxcar.rb in boxcars-0.2.16 vs lib/boxcars/boxcar.rb in boxcars-0.3.1

- old
+ new

@@ -61,21 +61,26 @@ # @param kwargs [Hash] The keyword arguments to pass to the boxcar. # you can pass one or the other, but not both. # @return [String] The answer to the question. def run(*args, **kwargs) rv = conduct(*args, **kwargs) - rv.is_a?(Result) ? rv.to_answer : rv + rv = rv[:answer] if rv.is_a?(Hash) && rv.key?(:answer) + return rv.answer if rv.is_a?(Result) + return rv[output_keys[0]] if rv.is_a?(Hash) + + rv end # Get an extended answer from the boxcar. # @param args [Array] The positional arguments to pass to the boxcar. # @param kwargs [Hash] The keyword arguments to pass to the boxcar. # you can pass one or the other, but not both. # @return [Boxcars::Result] The answer to the question. def conduct(*args, **kwargs) Boxcars.info "> Entering #{name}#run", :gray, style: :bold rv = depart(*args, **kwargs) + remember_history(rv) Boxcars.info "< Exiting #{name}#run", :gray, style: :bold rv end # helpers for conversation prompt building @@ -92,12 +97,52 @@ # user message def self.user(*strs) [:user, strs.join] end + # history entries + def self.hist + [:history, ""] + end + + # save this boxcar to a file + def save(path:) + File.write(path, YAML.dump(self)) + end + + # load this boxcar from a file + # rubocop:disable Security/YAMLLoad + def load(path:) + YAML.load(File.read(path)) + end + # rubocop:enable Security/YAMLLoad + private + # remember the history of this boxcar. Take the current intermediate steps and + # create a history that can be used on the next run. + # @param current_results [Array<Hash>] The current results. + def remember_history(current_results) + return unless current_results[:intermediate_steps] && is_a?(Train) + + # insert conversation history into the prompt + history = [] + history << Boxcar.user("Question: #{current_results[:input]}") + current_results[:intermediate_steps].each do |action, obs| + if action.is_a?(TrainAction) + obs = Observation.new(status: :ok, note: obs) if obs.is_a?(String) + next if obs.status != :ok + + history << Boxcar.assi("Thought: #{action.log}\n", "Observation: #{obs.note}") + else + Boxcars.error "Unknown action: #{action}", :red + end + end + history << Boxcar.assi("Thought: I know the final answer\nFinal Answer: #{current_results[:output]}") + prompt.add_history(history) + end + # Get an answer from the boxcar. def run_boxcar(inputs:, return_only_outputs: false) inputs = our_inputs(inputs) output = nil begin @@ -115,17 +160,15 @@ # line up parameters and run boxcar def depart(*args, **kwargs) if kwargs.empty? raise Boxcars::ArgumentError, "run supports only one positional argument." if args.length != 1 - return run_boxcar(inputs: args[0])[output_keys.first] + return run_boxcar(inputs: args[0]) end - if args.empty? - ans = run_boxcar(inputs: kwargs) - return ans[output_keys.first] - end + return run_boxcar(inputs: kwargs) if args.empty? + raise Boxcars::ArgumentError, "run supported with either positional or keyword arguments but not both. Got args" \ ": #{args} and kwargs: #{kwargs}." end def our_inputs(inputs) @@ -146,9 +189,10 @@ Result.from_text(text) end end end +require "boxcars/observation" require "boxcars/result" require "boxcars/boxcar/engine_boxcar" require "boxcars/boxcar/calculator" require "boxcars/boxcar/google_search" require "boxcars/boxcar/wikipedia_search"