boxcars 0.1.7 → 0.1.8

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: f8cfde09f23575d2b54249bd2b6d2c15697092b7c52db4d5f0546bb0113a3949
4
- data.tar.gz: d557f681bf8a26251608b17038650868563da9d54753789c568331328cfa456b
3
+ metadata.gz: 3de375ad403bb62fb6af1045aff6a6115cbb598c3747fe48f882fb40483289e0
4
+ data.tar.gz: 343a3077d72ce21a56d8045701a8a3bd681c5fe91fd8ffbca2cc14270b92f3bb
5
5
  SHA512:
6
- metadata.gz: db5af829a8a6e600cbb402e53aa7aaf1f9374725c5cf1d61ee908cb58ffda305b03ee00a4664e9f1134dc6887be9dab8c7877ad4c6b981e5a5665bfc1cfec2f3
7
- data.tar.gz: 17930e46fa46b4d1a268367aff6d9b5851fac890f00d5a87e722ed3833552bb851614a5ab606cb9a08afce611a5882c9838094e31c1d34b9d17c05923656fc38
6
+ metadata.gz: efc72210fb52599b7c6278502a5b4143d995e671c62c7f6c090cbddf2a8926b231b0d7ab0aa28fa1325324ded1ebac5cac4e10e608ae59077a431a20f9d62f23
7
+ data.tar.gz: eeb00a993d7bbf64ac5c7461a1e31f241407c58a19a919c0853ade7e4a3bf717ab4f69331c5bc5d8c0049a89c53353d311d41616352131379b7e87b8ec3e491d
data/.env_sample ADDED
@@ -0,0 +1,2 @@
1
+ openai_access_token: ''
2
+ serpapi_api_key: ''
data/CHANGELOG.md CHANGED
@@ -1,8 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased](https://github.com/BoxcarsAI/boxcars/tree/HEAD)
3
+ ## [v0.1.7](https://github.com/BoxcarsAI/boxcars/tree/v0.1.7) (2023-02-27)
4
4
 
5
- [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.5...HEAD)
5
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.6...v0.1.7)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - figure out logging [\#10](https://github.com/BoxcarsAI/boxcars/issues/10)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - Fix typos in README concepts [\#26](https://github.com/BoxcarsAI/boxcars/pull/26) ([MasterOdin](https://github.com/MasterOdin))
14
+
15
+ ## [v0.1.6](https://github.com/BoxcarsAI/boxcars/tree/v0.1.6) (2023-02-24)
16
+
17
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.5...v0.1.6)
6
18
 
7
19
  **Implemented enhancements:**
8
20
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.1.7)
4
+ boxcars (0.1.8)
5
5
  google_search_results (~> 2.2)
6
6
  ruby-openai (~> 3.0)
7
7
 
@@ -7,7 +7,7 @@ module Boxcars
7
7
  # the description of this engine boxcar
8
8
  ARDESC = "useful for when you need to query a database for an application named %<name>s."
9
9
  LOCKED_OUT_MODELS = %w[ActiveRecord::SchemaMigration ActiveRecord::InternalMetadata ApplicationRecord].freeze
10
- attr_accessor :connection, :input_key, :requested_models, :read_only, :approval_callback
10
+ attr_accessor :connection, :requested_models, :read_only, :approval_callback
11
11
  attr_reader :except_models
12
12
 
13
13
  # @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
@@ -15,43 +15,25 @@ module Boxcars
15
15
  # @param read_only [Boolean] Whether to use read only models. Defaults to true unless you pass an approval function.
16
16
  # @param approval_callback [Proc] A function to call to approve changes. Defaults to nil.
17
17
  # @param kwargs [Hash] Any other keyword arguments. These can include:
18
- # :name, :description, :prompt, :input_key, :output_key and :except_models
18
+ # :name, :description, :prompt, :except_models, :top_k, and :stop
19
19
  def initialize(engine: nil, models: nil, read_only: nil, approval_callback: nil, **kwargs)
20
20
  check_models(models)
21
21
  @except_models = LOCKED_OUT_MODELS + kwargs[:except_models].to_a
22
22
  @approval_callback = approval_callback
23
23
  @read_only = read_only.nil? ? !approval_callback : read_only
24
- @input_key = kwargs[:input_key] || :question
25
- @output_key = kwargs[:output_key] || :answer
26
24
  the_prompt = kwargs[prompt] || my_prompt
27
25
  name = kwargs[:name] || "Data"
26
+ kwargs[:stop] ||= ["Answer:"]
28
27
  super(name: name,
29
28
  description: kwargs[:description] || format(ARDESC, name: name),
30
29
  engine: engine,
31
30
  prompt: the_prompt,
32
- output_key: output_key)
31
+ **kwargs)
33
32
  end
34
33
 
35
- # the input keys for the prompt
36
- # @return [Array<Symbol>] The input keys for the prompt.
37
- def input_keys
38
- [input_key]
39
- end
40
-
41
- # the output keys for the prompt
42
- # @return [Array<Symbol>] The output keys for the prompt.
43
- def output_keys
44
- [output_key]
45
- end
46
-
47
- # call the boxcar
48
- # @param inputs [Hash] The inputs to the boxcar.
49
- # @return [Hash] The outputs from the boxcar.
50
- def call(inputs:)
51
- t = predict(question: inputs[input_key], top_k: 5, model_info: model_info, stop: ["Answer:"]).strip
52
- answer = get_answer(t)
53
- Boxcars.info answer, :magenta
54
- { output_key => answer }
34
+ # @return Hash The additional variables for this boxcar.
35
+ def prediction_additional
36
+ { model_info: model_info }.merge super
55
37
  end
56
38
 
57
39
  private
@@ -83,7 +65,7 @@ module Boxcars
83
65
 
84
66
  def model_info
85
67
  models = wanted_models
86
- models.pretty_inspect
68
+ models.inspect
87
69
  end
88
70
 
89
71
  # to be safe, we wrap the code in a transaction and rollback
@@ -167,13 +149,12 @@ module Boxcars
167
149
  output = 0 if output.is_a?(Array) && output.empty?
168
150
  output = output.first if output.is_a?(Array) && output.length == 1
169
151
  output = output[output.keys.first] if output.is_a?(Hash) && output.length == 1
170
- "Answer: #{output.inspect}"
152
+ "Answer: #{output.to_json}"
171
153
  rescue StandardError => e
172
154
  "Error: #{e.message}"
173
155
  end
174
156
 
175
157
  def get_answer(text)
176
- # debugger
177
158
  case text
178
159
  when /^ARCode:/
179
160
  get_active_record_answer(text)
@@ -209,7 +190,8 @@ module Boxcars
209
190
 
210
191
  # The prompt to use for the engine.
211
192
  def my_prompt
212
- @my_prompt ||= Prompt.new(input_variables: [:question, :top_k, :model_info], template: TEMPLATE)
193
+ @my_prompt ||= Prompt.new(input_variables: [:question], other_inputs: [:top_k], output_variables: [:answer],
194
+ template: TEMPLATE)
213
195
  end
214
196
  end
215
197
  end
@@ -6,42 +6,19 @@ module Boxcars
6
6
  class Calculator < EngineBoxcar
7
7
  # the description of this engine boxcar
8
8
  CALCDESC = "useful for when you need to answer questions about math"
9
- attr_accessor :input_key
10
9
 
11
10
  # @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
12
11
  # @param prompt [Boxcars::Prompt] The prompt to use for this boxcar. Defaults to built-in prompt.
13
- # @param input_key [Symbol] The key to use for the input. Defaults to :question.
14
- # @param output_key [Symbol] The key to use for the output. Defaults to :answer.
15
12
  # @param kwargs [Hash] Any other keyword arguments to pass to the parent class.
16
- def initialize(engine: nil, prompt: nil, input_key: :question, output_key: :answer, **kwargs)
17
- # def initialize(engine:, prompt: my_prompt, input_key: :question, output_key: :answer, **kwargs)
18
- @input_key = input_key
13
+ def initialize(engine: nil, prompt: nil, **kwargs)
14
+ # def initialize(engine:, prompt: my_prompt, output_key: :answer, **kwargs)
19
15
  the_prompt = prompt || my_prompt
16
+ kwargs[:stop] ||= ["```output"]
20
17
  super(name: kwargs[:name] || "Calculator",
21
18
  description: kwargs[:description] || CALCDESC,
22
19
  engine: engine,
23
20
  prompt: the_prompt,
24
- output_key: output_key)
25
- end
26
-
27
- # the prompt input keys
28
- def input_keys
29
- [input_key]
30
- end
31
-
32
- # the output keys
33
- def output_keys
34
- [output_key]
35
- end
36
-
37
- # call the calculator
38
- # @param inputs [Hash] The inputs to the boxcar.
39
- # @return [Hash] The outputs from the boxcar.
40
- def call(inputs:)
41
- t = predict(question: inputs[input_key], stop: ["```output"]).strip
42
- answer = get_answer(t)
43
- Boxcars.info answer, :magenta
44
- { output_key => answer }
21
+ **kwargs)
45
22
  end
46
23
 
47
24
  private
@@ -104,7 +81,7 @@ module Boxcars
104
81
 
105
82
  # The prompt to use for the engine.
106
83
  def my_prompt
107
- @my_prompt ||= Prompt.new(input_variables: [:question], template: TEMPLATE)
84
+ @my_prompt ||= Prompt.new(input_variables: [:question], output_variables: [:answer], template: TEMPLATE)
108
85
  end
109
86
  end
110
87
  end
@@ -4,17 +4,18 @@
4
4
  module Boxcars
5
5
  # For Boxcars that use an engine to do their work.
6
6
  class EngineBoxcar < Boxcar
7
- attr_accessor :prompt, :engine, :output_key
7
+ attr_accessor :prompt, :engine, :top_k, :stop
8
8
 
9
9
  # A Boxcar is a container for a single tool to run.
10
10
  # @param prompt [Boxcars::Prompt] The prompt to use for this boxcar with sane defaults.
11
11
  # @param name [String] The name of the boxcar. Defaults to classname.
12
12
  # @param description [String] A description of the boxcar.
13
13
  # @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
14
- def initialize(prompt:, engine: nil, output_key: "text", name: nil, description: nil)
14
+ def initialize(prompt:, engine: nil, name: nil, description: nil, **kwargs)
15
15
  @prompt = prompt
16
16
  @engine = engine || Boxcars.engine.new
17
- @output_key = output_key
17
+ @top_k = kwargs[:top_k] || 5
18
+ @stop = kwargs[:stop] || ["Answer:"]
18
19
  super(name: name, description: description)
19
20
  end
20
21
 
@@ -23,9 +24,14 @@ module Boxcars
23
24
  prompt.input_variables
24
25
  end
25
26
 
27
+ # the first input key for the prompt
28
+ def input_key
29
+ input_keys.first
30
+ end
31
+
26
32
  # output keys
27
33
  def output_keys
28
- [output_key]
34
+ prompt.output_variables
29
35
  end
30
36
 
31
37
  # generate a response from the engine
@@ -35,6 +41,7 @@ module Boxcars
35
41
  stop = input_list[0][:stop]
36
42
  prompts = []
37
43
  input_list.each do |inputs|
44
+ # prompt.missing_variables?(inputs)
38
45
  new_prompt = prompt.format(**inputs)
39
46
  Boxcars.debug("Prompt after formatting:\n#{new_prompt}", :cyan) if Boxcars.configuration.log_prompts
40
47
  prompts.push(new_prompt)
@@ -48,7 +55,7 @@ module Boxcars
48
55
  def apply(input_list:)
49
56
  response = generate(input_list: input_list)
50
57
  response.generations.to_h do |generation|
51
- [output_key, generation[0].text]
58
+ [output_keys.first, generation[0].text]
52
59
  end
53
60
  end
54
61
 
@@ -56,7 +63,7 @@ module Boxcars
56
63
  # @param kwargs [Hash] A hash of input values to use for the prompt.
57
64
  # @return [String] The output value.
58
65
  def predict(**kwargs)
59
- apply(input_list: [kwargs])[output_key]
66
+ apply(input_list: [kwargs])[output_keys.first]
60
67
  end
61
68
 
62
69
  # predict a response from the engine and parse it
@@ -77,7 +84,7 @@ module Boxcars
77
84
  def apply_and_parse(input_list:)
78
85
  result = apply(input_list: input_list)
79
86
  if prompt.output_parser
80
- result.map { |r| prompt.output_parser.parse(r[output_key]) }
87
+ result.map { |r| prompt.output_parser.parse(r[output_keys.first]) }
81
88
  else
82
89
  result
83
90
  end
@@ -90,5 +97,32 @@ module Boxcars
90
97
 
91
98
  raise Boxcars::ArgumentError, "run not supported when there is not exactly one output key. Got #{output_keys}."
92
99
  end
100
+
101
+ # call the boxcar
102
+ # @param inputs [Hash] The inputs to the boxcar.
103
+ # @return [Hash] The outputs from the boxcar.
104
+ def call(inputs:)
105
+ t = predict(**prediction_variables(inputs)).strip
106
+ answer = get_answer(t)
107
+ Boxcars.debug answer, :magenta
108
+ { output_keys.first => answer }
109
+ end
110
+
111
+ # @param inputs [Hash] The inputs to the boxcar.
112
+ # @return Hash The input variable for this boxcar.
113
+ def prediction_input(inputs)
114
+ { input_key => inputs[input_key] }
115
+ end
116
+
117
+ # @return Hash The additional variables for this boxcar.
118
+ def prediction_additional
119
+ { stop: stop, top_k: top_k }
120
+ end
121
+
122
+ # @param inputs [Hash] The inputs to the boxcar.
123
+ # @return Hash The variables for this boxcar.
124
+ def prediction_variables(inputs)
125
+ prediction_input(inputs).merge(prediction_additional)
126
+ end
93
127
  end
94
128
  end
@@ -6,46 +6,26 @@ module Boxcars
6
6
  class SQL < EngineBoxcar
7
7
  # the description of this engine boxcar
8
8
  SQLDESC = "useful for when you need to query a database for %<name>s."
9
- attr_accessor :connection, :input_key
9
+ attr_accessor :connection
10
10
 
11
11
  # @param connection [ActiveRecord::Connection] The SQL connection to use for this boxcar.
12
12
  # @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
13
- # @param input_key [Symbol] The key to use for the input. Defaults to :question.
14
- # @param output_key [Symbol] The key to use for the output. Defaults to :answer.
15
13
  # @param kwargs [Hash] Any other keyword arguments to pass to the parent class. This can include
16
- # :name, :description and :prompt
17
- def initialize(connection: nil, engine: nil, input_key: :question, output_key: :answer, **kwargs)
14
+ # :name, :description, :prompt and :top_k
15
+ def initialize(connection: nil, engine: nil, **kwargs)
18
16
  @connection = connection || ::ActiveRecord::Base.connection
19
- @input_key = input_key
20
17
  the_prompt = kwargs[prompt] || my_prompt
21
- name = kwargs[:name] || "data"
18
+ kwargs[:stop] ||= ["Answer:"]
19
+ name = kwargs[:name] || "database"
22
20
  super(name: name,
23
21
  description: kwargs[:description] || format(SQLDESC, name: name),
24
22
  engine: engine,
25
- prompt: the_prompt,
26
- output_key: output_key)
23
+ prompt: the_prompt)
27
24
  end
28
25
 
29
- # the input keys for the prompt
30
- # @return [Array<Symbol>] The input keys for the prompt.
31
- def input_keys
32
- [input_key]
33
- end
34
-
35
- # the output keys for the prompt
36
- # @return [Array<Symbol>] The output keys for the prompt.
37
- def output_keys
38
- [output_key]
39
- end
40
-
41
- # call the boxcar
42
- # @param inputs [Hash] The inputs to the boxcar.
43
- # @return [Hash] The outputs from the boxcar.
44
- def call(inputs:)
45
- t = predict(question: inputs[input_key], dialect: dialect, top_k: 5, table_info: schema, stop: ["Answer:"]).strip
46
- answer = get_answer(t)
47
- Boxcars.debug answer, :magenta
48
- { output_key => answer }
26
+ # @return Hash The additional variables for this boxcar.
27
+ def prediction_additional
28
+ { schema: schema, dialect: dialect }.merge super
49
29
  end
50
30
 
51
31
  private
@@ -66,7 +46,6 @@ module Boxcars
66
46
  end
67
47
 
68
48
  def dialect
69
- # connection.instance_variable_get "@config"[:adapter]
70
49
  connection.class.name.split("::").last.sub("Adapter", "")
71
50
  end
72
51
 
@@ -107,14 +86,18 @@ module Boxcars
107
86
  Answer: "Final answer here"
108
87
 
109
88
  Only use the following tables:
110
- %<table_info>s
89
+ %<schema>s
111
90
 
112
91
  Question: %<question>s
113
92
  IPT
114
93
 
115
94
  # The prompt to use for the engine.
116
95
  def my_prompt
117
- @my_prompt ||= Prompt.new(input_variables: [:question, :dialect, :top_k], template: TEMPLATE)
96
+ @my_prompt ||= Prompt.new(
97
+ input_variables: [:question],
98
+ other_inputs: [:top_k, :dialect, :table_info],
99
+ output_variables: [:answer],
100
+ template: TEMPLATE)
118
101
  end
119
102
  end
120
103
  end
@@ -77,7 +77,7 @@ module Boxcars
77
77
  begin
78
78
  output = call(inputs: inputs)
79
79
  rescue StandardError => e
80
- error "Error in #{name} boxcar#call: #{e}", :red
80
+ Boxcars.error "Error in #{name} boxcar#call: #{e}", :red
81
81
  raise e
82
82
  end
83
83
  validate_outputs(outputs: output.keys)
@@ -83,6 +83,25 @@ module Boxcars
83
83
  end
84
84
  end
85
85
 
86
+ # make sure we got a valid response
87
+ # @param response [Hash] The response to check.
88
+ # @param must_haves [Array<String>] The keys that must be in the response. Defaults to %w[choices].
89
+ # @raise [KeyError] if there is an issue with the access token.
90
+ # @raise [ValueError] if the response is not valid.
91
+ def check_response(response, must_haves: %w[choices])
92
+ if response['error']
93
+ code = response.dig('error', 'code')
94
+ msg = response.dig('error', 'message') || 'unknown error'
95
+ raise KeyError, "OPENAI_ACCESS_TOKEN not valid" if code == 'invalid_api_key'
96
+
97
+ raise ValueError, "OpenAI error: #{msg}"
98
+ end
99
+
100
+ must_haves.each do |key|
101
+ raise ValueError, "Expecting key #{key} in response" unless response.key?(key)
102
+ end
103
+ end
104
+
86
105
  # Call out to OpenAI's endpoint with k unique prompts.
87
106
  # @param prompts [Array<String>] The prompts to pass into the model.
88
107
  # @param stop [Array<String>] Optional list of stop words to use when generating.
@@ -98,6 +117,7 @@ module Boxcars
98
117
  sub_prompts = prompts.each_slice(batch_size).to_a
99
118
  sub_prompts.each do |sprompts|
100
119
  response = client(prompt: sprompts, **params)
120
+ check_response(response)
101
121
  choices.concat(response["choices"])
102
122
  keys_to_use = inkeys & response["usage"].keys
103
123
  keys_to_use.each { |key| token_usage[key] = token_usage[key].to_i + response["usage"][key] }
@@ -3,25 +3,44 @@
3
3
  module Boxcars
4
4
  # used by Boxcars that have engine's to create a prompt.
5
5
  class Prompt
6
- attr_reader :template, :input_variables, :output_variables
6
+ attr_reader :template, :input_variables, :other_inputs, :output_variables
7
7
 
8
8
  # @param template [String] The template to use for the prompt.
9
- # @param input_variables [Array<Symbol>] The input vars to use for the prompt.
10
- # @param output_variables [Array<Symbol>] The output vars to use for the prompt. Defaults to [:agent_scratchpad]
11
- def initialize(template:, input_variables:, output_variables: [:agent_scratchpad])
9
+ # @param input_variables [Array<Symbol>] The input vars to use for the prompt. Defaults to [:input]
10
+ # @param other_inputs [Array<Symbol>] The other input vars to use for the prompt. Defaults to []
11
+ # @param output_variables [Array<Symbol>] The output vars to use for the prompt. Defaults to [:output]
12
+ def initialize(template:, input_variables: nil, other_inputs: nil, output_variables: nil)
12
13
  @template = template
13
- @input_variables = input_variables
14
- @output_variables = output_variables
14
+ @input_variables = input_variables || [:input]
15
+ @other_inputs = other_inputs || []
16
+ @output_variables = output_variables || [:output]
15
17
  end
16
18
 
17
19
  # format the prompt with the input variables
20
+ # @param inputs [Hash] The inputs to use for the prompt.
21
+ # @return [String] The formatted prompt.
22
+ # @raise [Boxcars::KeyError] if the template has extra keys.
18
23
  def format(inputs)
19
24
  @template % inputs
25
+ rescue ::KeyError => e
26
+ first_line = e.message.to_s.split("\n").first
27
+ Boxcars.error "Missing prompt input key: #{first_line}"
28
+ raise KeyError, "Prompt format error: #{first_line}"
20
29
  end
21
30
 
22
31
  # check if the template is valid
23
32
  def template_is_valid?
24
- @template.include?("%<input>s") && @template.include?("%<agent_scratchpad>s")
33
+ all_vars = (input_variables + other_inputs + output_variables).sort
34
+ template_vars = @template.scan(/%<(\w+)>s/).flatten.map(&:to_sym).sort
35
+ all_vars == template_vars
36
+ end
37
+
38
+ # missing variables in the template
39
+ def missing_variables?(inputs)
40
+ input_vars = [input_variables, other_inputs].flatten.sort
41
+ return if inputs.keys.sort == input_vars
42
+
43
+ raise ArgumentError, "Missing expected input keys, got: #{inputs.keys}. Expected: #{input_vars}"
25
44
  end
26
45
 
27
46
  # create a prompt template from examples
@@ -29,17 +48,22 @@ module Boxcars
29
48
  # @param input_variables [Array<Symbol>] The input variables to use for the prompt.
30
49
  # @param example_separator [String] The separator to use between the examples. Defaults to "\n\n"
31
50
  # @param prefix [String] The prefix to use for the template. Defaults to ""
32
- def self.from_examples(examples:, suffix:, input_variables:, example_separator: "\n\n", prefix: "")
51
+ def self.from_examples(examples:, suffix:, input_variables:, example_separator: "\n\n", prefix: "", **kwargs)
33
52
  template = [prefix, examples, suffix].join(example_separator)
34
- Prompt.new(template: template, input_variables: input_variables)
53
+ other_inputs = kwargs[:other_inputs] || []
54
+ output_variables = kwargs[:output_variables] || [:output]
55
+ Prompt.new(template: template, input_variables: input_variables, other_inputs: other_inputs,
56
+ output_variables: output_variables)
35
57
  end
36
58
 
37
59
  # create a prompt template from a file
38
60
  # @param path [String] The path to the file to use for the template.
39
- # @param input_variables [Array<Symbol>] The input variables to use for the prompt.
40
- def self.from_file(path:, input_variables:)
61
+ # @param input_variables [Array<Symbol>] The input variables to use for the prompt. Defaults to [:input]
62
+ # @param output_variables [Array<Symbol>] The output variables to use for the prompt. Defaults to [:output]
63
+ def self.from_file(path:, input_variables: nil, other_inputs: nil, output_variables: nil)
41
64
  template = File.read(path)
42
- Prompt.new(template: template, input_variables: input_variables)
65
+ Prompt.new(template: template, input_variables: input_variables, other_inputs: other_inputs,
66
+ output_variables: output_variables)
43
67
  end
44
68
  end
45
69
  end
@@ -19,6 +19,7 @@ module Boxcars
19
19
  ... (this Thought/Action/Action Input/Observation sequence can repeat N times)
20
20
  Thought: I now know the final answer
21
21
  Final Answer: the final answer to the original input question
22
+ Next Actions: up to three suggested actions for the user to take next
22
23
  FINPUT
23
24
 
24
25
  # default prompt suffix
data/lib/boxcars/train.rb CHANGED
@@ -16,7 +16,7 @@ module Boxcars
16
16
  @name = name || self.class.name
17
17
  @return_values = [:output]
18
18
  @return_intermediate_steps = kwargs[:return_intermediate_steps] || false
19
- @max_iterations = kwargs[:max_iterations]
19
+ @max_iterations = kwargs[:max_iterations] || 25
20
20
  @early_stopping_method = kwargs[:early_stopping_method] || "force"
21
21
 
22
22
  super(prompt: prompt, engine: engine, name: kwargs[:name], description: kwargs[:description])
@@ -137,8 +137,6 @@ module Boxcars
137
137
  case prompt
138
138
  when Prompt
139
139
  prompt.template += "\n%<agent_scratchpad>s"
140
- # when FewShotPromptTemplate
141
- # prompt.suffix += "\n%<agent_scratchpad>s"
142
140
  else
143
141
  raise ValueError, "Got unexpected prompt type #{type(prompt)}"
144
142
  end
@@ -199,7 +197,7 @@ module Boxcars
199
197
  return_direct = boxcar.return_direct
200
198
  rescue StandardError => e
201
199
  error "Error in #{boxcar.name} boxcar#call: #{e}", :red
202
- raise e
200
+ observation = "Error - #{e}, correct and try again."
203
201
  end
204
202
  else
205
203
  observation = "#{output.boxcar} is not a valid boxcar, try another one."
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.1.7"
5
+ VERSION = "0.1.8"
6
6
  end
data/lib/boxcars.rb CHANGED
@@ -19,6 +19,9 @@ module Boxcars
19
19
  # Error class for all Boxcars security errors.
20
20
  class SecurityError < Error; end
21
21
 
22
+ # Error class for all Boxcars key errors.
23
+ class KeyError < Error; end
24
+
22
25
  # Configuration contains gem settings
23
26
  class Configuration
24
27
  attr_writer :openai_access_token, :serpapi_api_key
@@ -50,18 +53,18 @@ module Boxcars
50
53
  end
51
54
 
52
55
  def key_lookup(key, kwargs)
53
- rv = if kwargs.key?(key) && !kwargs[key].nil?
54
- # override with kwargs if present
55
- kwargs[key]
56
- elsif (set_val = instance_variable_get("@#{key}"))
57
- # use saved value if present
58
- set_val
59
- else
60
- # otherwise, dig out of the environment
61
- new_key = ENV.fetch(key.to_s.upcase, nil)
62
- new_key
63
- end
64
- check_key(key, rv)
56
+ val = if kwargs.key?(key) && !kwargs[key].nil?
57
+ # override with kwargs if present
58
+ kwargs[key]
59
+ elsif (provided_val = instance_variable_get("@#{key}"))
60
+ # use saved value if present. Set using Boxcars::configuration.the_key = "abcde"
61
+ provided_val
62
+ else
63
+ # otherwise, dig out of the environment
64
+ env_val = ENV.fetch(key.to_s.upcase, nil)
65
+ env_val
66
+ end
67
+ check_key(key, val)
65
68
  end
66
69
  end
67
70
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boxcars
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.7
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francis Sullivan
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-02-27 00:00:00.000000000 Z
12
+ date: 2023-03-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug
@@ -89,6 +89,7 @@ executables: []
89
89
  extensions: []
90
90
  extra_rdoc_files: []
91
91
  files:
92
+ - ".env_sample"
92
93
  - ".rspec"
93
94
  - ".rubocop.yml"
94
95
  - CHANGELOG.md