boxcars 0.1.8 → 0.2.0

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: 3de375ad403bb62fb6af1045aff6a6115cbb598c3747fe48f882fb40483289e0
4
- data.tar.gz: 343a3077d72ce21a56d8045701a8a3bd681c5fe91fd8ffbca2cc14270b92f3bb
3
+ metadata.gz: 34001190ca60f2b9fe68d603267ffccaaef398cae2f8054e34d6d0926fd8bf9d
4
+ data.tar.gz: 7918d0bad50e6758490a9baa58393e38071e524b0d284c43dd479cf1d091deab
5
5
  SHA512:
6
- metadata.gz: efc72210fb52599b7c6278502a5b4143d995e671c62c7f6c090cbddf2a8926b231b0d7ab0aa28fa1325324ded1ebac5cac4e10e608ae59077a431a20f9d62f23
7
- data.tar.gz: eeb00a993d7bbf64ac5c7461a1e31f241407c58a19a919c0853ade7e4a3bf717ab4f69331c5bc5d8c0049a89c53353d311d41616352131379b7e87b8ec3e491d
6
+ metadata.gz: dacd721802478a783ac9c50c4ebd959764b7601254c3a4b94546f093177cd94bdb4636d9f635154e6419a7d8505152ac7092c491238baab8ac0e47277323a7af
7
+ data.tar.gz: 73c638b8486681e3268ff94e390550f565c011891e9c025556f41df4e0e741ae705fa9fdeb6c3d1996919344abbfff84a8f1454e22a5d108dcae6d65e4718403
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.1.8)
4
+ boxcars (0.2.0)
5
5
  google_search_results (~> 2.2)
6
6
  ruby-openai (~> 3.0)
7
7
 
@@ -140,7 +140,7 @@ GEM
140
140
  rubocop-rspec (2.18.1)
141
141
  rubocop (~> 1.33)
142
142
  rubocop-capybara (~> 2.17)
143
- ruby-openai (3.3.0)
143
+ ruby-openai (3.5.0)
144
144
  httparty (>= 0.18.1)
145
145
  ruby-progressbar (1.11.0)
146
146
  ruby2_keywords (0.0.5)
@@ -11,7 +11,6 @@ module Boxcars
11
11
  # @param prompt [Boxcars::Prompt] The prompt to use for this boxcar. Defaults to built-in prompt.
12
12
  # @param kwargs [Hash] Any other keyword arguments to pass to the parent class.
13
13
  def initialize(engine: nil, prompt: nil, **kwargs)
14
- # def initialize(engine:, prompt: my_prompt, output_key: :answer, **kwargs)
15
14
  the_prompt = prompt || my_prompt
16
15
  kwargs[:stop] ||= ["```output"]
17
16
  super(name: kwargs[:name] || "Calculator",
@@ -45,7 +44,7 @@ module Boxcars
45
44
  TEMPLATE = <<~'IPT'
46
45
  You are GPT-3, and you can't do math.
47
46
  You can do basic math, and your memorization abilities are impressive, but you can't do any complex calculations that a human could not do in their head. You also have an annoying tendency to just make up highly specific, but wrong, answers.
48
- So we hooked you up to a Ruby 3 kernel, and now you can execute ruby code. If anyone gives you a hard math problem, just use this format and we’ll take care of the rest:
47
+ So we hooked you up to a Ruby 3 kernel, and now you can execute code written in the Ruby programming language. If anyone gives you a hard math problem, just use this format and we’ll take care of the rest:
49
48
 
50
49
  Question: ${{Question with hard calculation.}}
51
50
  ```ruby
@@ -52,8 +52,11 @@ module Boxcars
52
52
  def get_embedded_sql_answer(text)
53
53
  code = text[/^SQLQuery: (.*)/, 1]
54
54
  Boxcars.debug code, :yellow
55
- output = connection.exec_query(code).to_a
56
- "Answer: #{output}"
55
+ output = connection.exec_query(code)
56
+ output = 0 if output.is_a?(Array) && output.empty?
57
+ output = output.first if output.is_a?(Array) && output.length == 1
58
+ output = output[output.keys.first] if output.is_a?(Hash) && output.length == 1
59
+ "Answer: #{output.to_json}"
57
60
  end
58
61
 
59
62
  def get_answer(text)
@@ -111,6 +111,11 @@ module Boxcars
111
111
  end
112
112
  validate_inputs(inputs: inputs)
113
113
  end
114
+
115
+ # the default answer is the text passed in
116
+ def get_answer(text)
117
+ text
118
+ end
114
119
  end
115
120
  end
116
121
 
@@ -9,9 +9,9 @@ module Boxcars
9
9
 
10
10
  # The default parameters to use when asking the engine.
11
11
  DEFAULT_PARAMS = {
12
- model: "text-davinci-003",
12
+ model: "gpt-3.5-turbo",
13
13
  temperature: 0.7,
14
- max_tokens: 256
14
+ max_tokens: 512
15
15
  }.freeze
16
16
 
17
17
  # the default name of the engine
@@ -43,7 +43,13 @@ module Boxcars
43
43
  organization_id = Boxcars.configuration.organization_id
44
44
  clnt = ::OpenAI::Client.new(access_token: access_token, organization_id: organization_id)
45
45
  the_params = { prompt: prompt }.merge(open_ai_params).merge(kwargs)
46
- clnt.completions(parameters: the_params)
46
+ if the_params[:model] == "gpt-3.5-turbo"
47
+ prompt = prompt.first if prompt.is_a?(Array)
48
+ the_params = { messages: [{ role: "user", content: prompt }] }.merge(open_ai_params).merge(kwargs)
49
+ clnt.chat(parameters: the_params)
50
+ else
51
+ clnt.completions(parameters: the_params)
52
+ end
47
53
  end
48
54
 
49
55
  # get an answer from the engine for a question.
@@ -51,7 +57,7 @@ module Boxcars
51
57
  # @param kwargs [Hash] Additional parameters to pass to the engine if wanted.
52
58
  def run(question, **kwargs)
53
59
  response = client(prompt: question, **kwargs)
54
- answer = response["choices"].map { |c| c["text"] }.join("\n").strip
60
+ answer = response["choices"].map { |c| c.dig("message", "content") || c["text"] }.join("\n").strip
55
61
  puts answer
56
62
  answer
57
63
  end
@@ -74,7 +80,7 @@ module Boxcars
74
80
  def generation_info(sub_choices)
75
81
  sub_choices.map do |choice|
76
82
  Generation.new(
77
- text: choice["text"],
83
+ text: choice.dig("message", "content") || choice["text"],
78
84
  generation_info: {
79
85
  finish_reason: choice.fetch("finish_reason", nil),
80
86
  logprobs: choice.fetch("logprobs", nil)
@@ -160,7 +166,8 @@ module Boxcars
160
166
  'text-babbage-001': 2048,
161
167
  'text-ada-001': 2048,
162
168
  'code-davinci-002': 8000,
163
- 'code-cushman-001': 2048
169
+ 'code-cushman-001': 2048,
170
+ 'gpt-3.5-turbo-1': 4096
164
171
  }.freeze
165
172
  model_lookup[modelname] || 4097
166
173
  end
@@ -7,12 +7,19 @@ module Boxcars
7
7
  # @param code [String] The code to run
8
8
  def call(code:)
9
9
  Boxcars.debug "RubyREPL: #{code}", :yellow
10
+
11
+ # wrap the code in an excption block so we can catch errors
12
+ code = "begin\n#{code}\nrescue Exception => e\n puts 'Error: ' + e.message\nend"
10
13
  output = ""
11
14
  IO.popen("ruby", "r+") do |io|
12
15
  io.puts code
13
16
  io.close_write
14
17
  output = io.read
15
18
  end
19
+ if output =~ /^Error: /
20
+ Boxcars.error output
21
+ output
22
+ end
16
23
  Boxcars.debug "Answer: #{output}", :yellow, style: :bold
17
24
  output
18
25
  end
@@ -19,7 +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
+ Next Actions: If you have them, up to three suggested actions for the user to take after getting this answer.
23
23
  FINPUT
24
24
 
25
25
  # default prompt suffix
@@ -71,13 +71,15 @@ module Boxcars
71
71
  answer = engine_output.split(FINAL_ANSWER_ACTION).last.strip
72
72
  ['Final Answer', answer]
73
73
  else
74
+ # the thought should be the frist line here if it doesn't start with "Action:"
75
+ thought = engine_output.split(/\n+/).reject(&:empty?).first
76
+ Boxcars.debug("Though: #{thought}", :cyan)
74
77
  regex = /Action: (?<action>.*)\nAction Input: (?<action_input>.*)/
75
78
  match = regex.match(engine_output)
76
79
  raise ValueError, "Could not parse engine output: #{engine_output}" unless match
77
80
 
78
81
  action = match[:action].strip
79
- action_input = match[:action_input].strip
80
- # [action, action_input.strip(" ").strip('"')]
82
+ action_input = match[:action_input].strip.delete_prefix('"').delete_suffix('"')
81
83
  [action, action_input]
82
84
  end
83
85
  end
data/lib/boxcars/train.rb CHANGED
@@ -38,7 +38,7 @@ module Boxcars
38
38
  def construct_scratchpad(intermediate_steps)
39
39
  thoughts = ""
40
40
  intermediate_steps.each do |action, observation|
41
- thoughts += action.is_a?(String) ? action : action.log
41
+ thoughts += action.is_a?(String) ? action : " #{action.log}"
42
42
  thoughts += "\n#{observation_prefix}#{observation}\n#{engine_prefix}"
43
43
  end
44
44
  thoughts
@@ -196,7 +196,7 @@ module Boxcars
196
196
  observation = boxcar.run(output.boxcar_input)
197
197
  return_direct = boxcar.return_direct
198
198
  rescue StandardError => e
199
- error "Error in #{boxcar.name} boxcar#call: #{e}", :red
199
+ Boxcars.error "Error in #{boxcar.name} boxcar#call: #{e}", :red
200
200
  observation = "Error - #{e}, correct and try again."
201
201
  end
202
202
  else
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.1.8"
5
+ VERSION = "0.2.0"
6
6
  end
data/lib/boxcars.rb CHANGED
@@ -30,7 +30,7 @@ module Boxcars
30
30
  def initialize
31
31
  @organization_id = nil
32
32
  @logger = Rails.logger if defined?(Rails)
33
- @log_prompts = false
33
+ @log_prompts = ENV.fetch("LOG_PROMPTS", false)
34
34
  end
35
35
 
36
36
  # @return [String] The OpenAI Access Token either from arg or env.
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.8
4
+ version: 0.2.0
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-03-02 00:00:00.000000000 Z
12
+ date: 2023-03-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug