boxcars 0.2.2 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -1
- data/Gemfile.lock +1 -1
- data/README.md +25 -13
- data/lib/boxcars/boxcar/active_record.rb +62 -36
- data/lib/boxcars/boxcar/engine_boxcar.rb +21 -4
- data/lib/boxcars/boxcar/google_search.rb +2 -2
- data/lib/boxcars/boxcar/sql.rb +7 -3
- data/lib/boxcars/train/zero_shot.rb +15 -10
- data/lib/boxcars/train.rb +7 -0
- data/lib/boxcars/version.rb +1 -1
- data/lib/boxcars.rb +2 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6a9d94c026cf616e590d293d4ef2b0c655ddc6e3ae40115b36ebbfbbee1cb9a4
|
4
|
+
data.tar.gz: 549a877fdf1b329f402f3a159420bc6599677bcd40f2776c8bea57fade099b14
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '082a569848bf46276dadf9e2461e1bded9e107a2ba344fed06382c98548aa78b5012c63cdeeb27f394783b25bb6dea6d6bd10382d1f0113b8de548a366ca2b4e'
|
7
|
+
data.tar.gz: 25452562685c57ba7ded3de67a4c27f7d15e9373f5370f061d75d9d4f32e4e1836e9ea6947bfef19d7a32fe6c130d4f816fe5d9529ea1db5f38f7b0bb2837ccb
|
data/CHANGELOG.md
CHANGED
@@ -2,7 +2,15 @@
|
|
2
2
|
|
3
3
|
## [Unreleased](https://github.com/BoxcarsAI/boxcars/tree/HEAD)
|
4
4
|
|
5
|
-
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.
|
5
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.2...HEAD)
|
6
|
+
|
7
|
+
**Merged pull requests:**
|
8
|
+
|
9
|
+
- better error handling and retry for Active Record Boxcar [\#39](https://github.com/BoxcarsAI/boxcars/pull/39) ([francis](https://github.com/francis))
|
10
|
+
|
11
|
+
## [v0.2.2](https://github.com/BoxcarsAI/boxcars/tree/v0.2.2) (2023-03-16)
|
12
|
+
|
13
|
+
[Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.2.1...v0.2.2)
|
6
14
|
|
7
15
|
**Implemented enhancements:**
|
8
16
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@
|
|
11
11
|
<a href="https://github.com/BoxcarsAI/boxcars/blob/main/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-informational" alt="License"></a>
|
12
12
|
</p>
|
13
13
|
|
14
|
-
Boxcars is a gem that enables you to create new systems with AI composability, using various concepts such as OpenAI, Search, SQL, Rails Active Record and more. This can even be extended with your concepts as well
|
14
|
+
Boxcars is a gem that enables you to create new systems with AI composability, using various concepts such as OpenAI, Search, SQL, Rails Active Record and more. This can even be extended with your concepts as well (including your concepts).
|
15
15
|
|
16
16
|
This gem was inspired by the popular Python library Langchain. However, we wanted to give it a Ruby spin and make it more user-friendly for beginners to get started.
|
17
17
|
|
@@ -23,6 +23,11 @@ All of these concepts are in a module named Boxcars:
|
|
23
23
|
- Prompt - used by an Engine to generate text results. Most of the Boxcars have built-in prompts, so you only need to worry about these if you are extending the system.
|
24
24
|
- Engine - an entity that generates text from a Prompt. OpenAI's LLM text generator is the default Engine if no other is specified.
|
25
25
|
|
26
|
+
## Security
|
27
|
+
Currently, our system is designed for individuals who already possess administrative privileges for their project. It is likely possible to manipulate the system's prompts to carry out malicious actions, but if you already have administrative access, you can perform such actions without requiring boxcars in the first place.
|
28
|
+
|
29
|
+
*Note:* We are actively seeking ways to improve our system's ability to identify and prevent any nefarious attempts from occurring. If you have any suggestions or recommendations, please feel free to share them with us by either finding an existing issue or creating a new one and providing us with your feedback.
|
30
|
+
|
26
31
|
## Installation
|
27
32
|
|
28
33
|
Add this line to your application's Gemfile:
|
@@ -66,10 +71,10 @@ Produces:
|
|
66
71
|
```text
|
67
72
|
> Entering Calculator#run
|
68
73
|
what is pi to the forth power divided by 22.1?
|
69
|
-
RubyREPL: puts(Math::PI**4
|
74
|
+
RubyREPL: puts (Math::PI**4)/22.1
|
70
75
|
Answer: 4.407651178009159
|
71
76
|
|
72
|
-
4.407651178009159
|
77
|
+
{"status":"ok","answer":"4.407651178009159","explanation":"Answer: 4.407651178009159","code":"puts (Math::PI**4)/22.1"}
|
73
78
|
< Exiting Calculator#run
|
74
79
|
4.407651178009159
|
75
80
|
```
|
@@ -94,27 +99,34 @@ Here is what we have so far, but please put up a PR with your new ideas.
|
|
94
99
|
# run a Train for a calculator, and search using default Engine
|
95
100
|
boxcars = [Boxcars::Calculator.new, Boxcars::Serp.new]
|
96
101
|
train = Boxcars.train.new(boxcars: boxcars)
|
97
|
-
|
102
|
+
train.run "What is pi times the square root of the average temperature in Austin TX in January?"
|
98
103
|
```
|
99
104
|
Produces:
|
100
105
|
```text
|
101
106
|
> Entering Zero Shot#run
|
102
107
|
What is pi times the square root of the average temperature in Austin TX in January?
|
108
|
+
Thought: We need to find the average temperature in Austin TX in January and then multiply it by pi and the square root of that value. We can use a search engine to find the average temperature and a calculator to perform the multiplication.
|
103
109
|
Question: Average temperature in Austin TX in January
|
104
110
|
Answer: increase from 62°F to 64°F
|
105
|
-
|
111
|
+
Observation: increase from 62°F to 64°F
|
112
|
+
Thought: The average temperature in Austin TX in January is around 63°F.
|
106
113
|
> Entering Calculator#run
|
107
|
-
|
108
|
-
RubyREPL: puts
|
109
|
-
Answer:
|
114
|
+
pi * sqrt(63)
|
115
|
+
RubyREPL: puts(Math::PI * Math.sqrt(63))
|
116
|
+
Answer: 24.935618646198247
|
110
117
|
|
111
|
-
|
118
|
+
{"status":"ok","answer":"24.935618646198247","explanation":"Answer: 24.935618646198247","code":"puts(Math::PI * Math.sqrt(63))"}
|
112
119
|
< Exiting Calculator#run
|
113
|
-
|
114
|
-
|
115
|
-
|
120
|
+
Observation: 24.935618646198247
|
121
|
+
The result of pi times the square root of the average temperature in Austin TX in January is approximately 24.94.
|
122
|
+
|
123
|
+
Final Answer: 24.94
|
124
|
+
|
125
|
+
Next Actions:
|
126
|
+
1. What is the average temperature in Austin TX in July?
|
127
|
+
2. What is the formula for calculating the area of a circle?
|
128
|
+
3. What is the value of pi to 10 decimal places?
|
116
129
|
< Exiting Zero Shot#run
|
117
|
-
201.06
|
118
130
|
```
|
119
131
|
### More Examples
|
120
132
|
See [this](https://github.com/BoxcarsAI/boxcars/blob/main/notebooks/boxcars_examples.ipynb) Jupyter Notebook for more examples.
|
@@ -71,13 +71,21 @@ module Boxcars
|
|
71
71
|
|
72
72
|
# to be safe, we wrap the code in a transaction and rollback
|
73
73
|
def rollback_after_running
|
74
|
-
|
74
|
+
result = nil
|
75
|
+
runtime_exception = nil
|
75
76
|
::ActiveRecord::Base.transaction do
|
76
|
-
|
77
|
+
begin
|
78
|
+
result = yield
|
79
|
+
rescue SecurityError, ::NameError, ::Error => e
|
80
|
+
Boxcars.error("Error while running code: #{e.message[0..60]} ...", :red)
|
81
|
+
runtime_exception = e
|
82
|
+
end
|
77
83
|
ensure
|
78
84
|
raise ::ActiveRecord::Rollback
|
79
85
|
end
|
80
|
-
|
86
|
+
raise runtime_exception if runtime_exception
|
87
|
+
|
88
|
+
result
|
81
89
|
end
|
82
90
|
|
83
91
|
# check for dangerous code that is outside of ActiveRecord
|
@@ -85,13 +93,22 @@ module Boxcars
|
|
85
93
|
bad_words = %w[commit drop_constraint drop_constraint! drop_extension drop_extension! drop_foreign_key drop_foreign_key! \
|
86
94
|
drop_index drop_index! drop_join_table drop_join_table! drop_materialized_view drop_materialized_view! \
|
87
95
|
drop_partition drop_partition! drop_schema drop_schema! drop_table drop_table! drop_trigger drop_trigger! \
|
88
|
-
drop_view drop_view! eval execute reset revoke rollback truncate
|
96
|
+
drop_view drop_view! eval instance_eval send system execute reset revoke rollback truncate \
|
97
|
+
encrypted_password].freeze
|
89
98
|
without_strings = code.gsub(/('([^'\\]*(\\.[^'\\]*)*)'|"([^"\\]*(\\.[^"\\]*)*"))/, 'XX')
|
90
|
-
|
99
|
+
|
100
|
+
if without_strings.include?("`")
|
101
|
+
Boxcars.info "code included possibly destructive backticks #{code}", :red
|
102
|
+
return false
|
103
|
+
end
|
104
|
+
|
105
|
+
word_list = without_strings.split(/[.,() :]/)
|
106
|
+
|
107
|
+
puts word_list.inspect
|
91
108
|
|
92
109
|
bad_words.each do |w|
|
93
110
|
if word_list.include?(w)
|
94
|
-
Boxcars.info "code included destructive instruction: #{w} #{code}", :red
|
111
|
+
Boxcars.info "code included possibly destructive instruction: '#{w}' in #{code}", :red
|
95
112
|
return false
|
96
113
|
end
|
97
114
|
end
|
@@ -122,8 +139,11 @@ module Boxcars
|
|
122
139
|
return true unless changes&.positive?
|
123
140
|
|
124
141
|
Boxcars.debug "#{name}(Pending Changes): #{changes}", :yellow
|
125
|
-
|
126
|
-
|
142
|
+
if read_only?
|
143
|
+
change_str = "#{changes} change#{'s' if changes.to_i > 1}"
|
144
|
+
Boxcars.error("Can not run code that makes #{change_str} in read-only mode", :red)
|
145
|
+
return false
|
146
|
+
end
|
127
147
|
|
128
148
|
return approval_callback.call(changes, code) if approval_callback.is_a?(Proc)
|
129
149
|
|
@@ -151,30 +171,34 @@ module Boxcars
|
|
151
171
|
output
|
152
172
|
end
|
153
173
|
|
154
|
-
def
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
when /^`(.+)`/
|
159
|
-
::Regexp.last_match(1)
|
160
|
-
else
|
161
|
-
code
|
162
|
-
end
|
174
|
+
def error_message(err, stage)
|
175
|
+
msg = err.message
|
176
|
+
msg = ::Regexp.last_match(1) if msg =~ /^(.+)' for #<Boxcars::ActiveRecord/
|
177
|
+
"#{stage} Error: #{msg} - please fix \"#{stage}:\" to not have this error"
|
163
178
|
end
|
164
179
|
|
165
180
|
def get_active_record_answer(text)
|
166
|
-
|
167
|
-
|
181
|
+
changes_code = extract_code text.split('ARCode:').first.split('ARChanges:').last.strip if text =~ /^ARChanges:/
|
182
|
+
code = extract_code text.split('ARCode:').last.strip
|
168
183
|
return Result.new(status: :ok, explanation: "code to run", code: code, changes_code: changes_code) if code_only?
|
169
184
|
|
170
|
-
|
185
|
+
have_approval = false
|
186
|
+
begin
|
187
|
+
have_approval = approved?(changes_code, code)
|
188
|
+
rescue NameError, Error => e
|
189
|
+
return Result.new(status: :error, explanation: error_message(e, "ARChanges"), changes_code: changes_code)
|
190
|
+
end
|
191
|
+
|
192
|
+
raise SecurityError, "Permission to run code that makes changes denied" unless have_approval
|
171
193
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
194
|
+
begin
|
195
|
+
output = clean_up_output(run_active_record_code(code))
|
196
|
+
Result.new(status: :ok, answer: output, explanation: "Answer: #{output.to_json}", code: code)
|
197
|
+
rescue SecurityError => e
|
198
|
+
raise e
|
199
|
+
rescue ::StandardError => e
|
200
|
+
Result.new(status: :error, answer: nil, explanation: error_message(e, "ARCode"), code: code)
|
201
|
+
end
|
178
202
|
end
|
179
203
|
|
180
204
|
def get_answer(text)
|
@@ -184,7 +208,8 @@ module Boxcars
|
|
184
208
|
when /^Answer:/
|
185
209
|
Result.from_text(text)
|
186
210
|
else
|
187
|
-
Result.from_error("
|
211
|
+
Result.from_error("Error: Your answer wasn't formatted properly - try again. I expected your answer to " \
|
212
|
+
"start with \"ARChanges:\" or \"ARCode:\"")
|
188
213
|
end
|
189
214
|
end
|
190
215
|
|
@@ -196,18 +221,19 @@ module Boxcars
|
|
196
221
|
"to at most %<top_k>s results.\n",
|
197
222
|
"Never query for all the columns from a specific model, ",
|
198
223
|
"only ask for the relevant attributes given the question.\n",
|
199
|
-
"Also, pay attention to which attribute is in which model
|
200
|
-
|
224
|
+
"Also, pay attention to which attribute is in which model.\n\n",
|
225
|
+
"Use the following format:\n",
|
201
226
|
"Question: ${{Question here}}\n",
|
202
|
-
"ARCode: ${{Active Record code to run}} - make sure you use valid code\n",
|
203
227
|
"ARChanges: ${{Active Record code to compute the number of records going to change}} - ",
|
204
|
-
"Only add this line if the ARCode on the line
|
205
|
-
"
|
206
|
-
|
207
|
-
"
|
208
|
-
"
|
228
|
+
"Only add this line if the ARCode on the next line will make data changes.\n",
|
229
|
+
"ARCode: ${{Active Record code to run}} - make sure you use valid code\n",
|
230
|
+
"Answer: ${{Final answer here}}\n\n",
|
231
|
+
"Only use the following Active Record models: %<model_info>s\n",
|
232
|
+
"Pay attention to use only the attribute names that you can see in the model description.\n",
|
233
|
+
"Do not make up variable or attribute names, and do not share variables between the code in ARChanges and ARCode\n",
|
234
|
+
"Be careful to not query for attributes that do not exist, and to use the format specified above.\n"
|
209
235
|
),
|
210
|
-
|
236
|
+
user("Question: %<question>s")
|
211
237
|
].freeze
|
212
238
|
|
213
239
|
# The prompt to use for the engine.
|
@@ -65,7 +65,9 @@ module Boxcars
|
|
65
65
|
# @param kwargs [Hash] A hash of input values to use for the prompt.
|
66
66
|
# @return [String] The output value.
|
67
67
|
def predict(current_conversation: nil, **kwargs)
|
68
|
-
apply(current_conversation: current_conversation, input_list: [kwargs])[output_keys.first]
|
68
|
+
prediction = apply(current_conversation: current_conversation, input_list: [kwargs])[output_keys.first]
|
69
|
+
Boxcars.debug(prediction, :white) if Boxcars.configuration.log_generated
|
70
|
+
prediction
|
69
71
|
end
|
70
72
|
|
71
73
|
# check that there is exactly one output key
|
@@ -84,11 +86,12 @@ module Boxcars
|
|
84
86
|
conversation = nil
|
85
87
|
answer = nil
|
86
88
|
4.times do
|
87
|
-
|
88
|
-
answer = get_answer(
|
89
|
+
text = predict(current_conversation: conversation, **prediction_variables(inputs)).strip
|
90
|
+
answer = get_answer(text)
|
89
91
|
if answer.status == :error
|
90
92
|
Boxcars.debug "have error, trying again: #{answer.answer}", :red
|
91
93
|
conversation ||= Conversation.new
|
94
|
+
conversation.add_assistant(text)
|
92
95
|
conversation.add_user(answer.answer)
|
93
96
|
else
|
94
97
|
Boxcars.debug answer.to_json, :magenta
|
@@ -97,7 +100,7 @@ module Boxcars
|
|
97
100
|
end
|
98
101
|
Boxcars.error answer.to_json, :red
|
99
102
|
{ output_key => "Error: #{answer}" }
|
100
|
-
rescue Boxcars::ConfigurationError => e
|
103
|
+
rescue Boxcars::ConfigurationError, Boxcars::SecurityError => e
|
101
104
|
raise e
|
102
105
|
rescue Boxcars::Error => e
|
103
106
|
Boxcars.error e.message, :red
|
@@ -120,5 +123,19 @@ module Boxcars
|
|
120
123
|
def prediction_variables(inputs)
|
121
124
|
prediction_input(inputs).merge(prediction_additional)
|
122
125
|
end
|
126
|
+
|
127
|
+
# remove backticks or triple backticks from the code
|
128
|
+
# @param code [String] The code to remove backticks from.
|
129
|
+
# @return [String] The code without backticks.
|
130
|
+
def extract_code(code)
|
131
|
+
case code
|
132
|
+
when /^```\w*/
|
133
|
+
code.split(/```\w*\n/).last.split('```').first.strip
|
134
|
+
when /^`(.+)`/
|
135
|
+
::Regexp.last_match(1)
|
136
|
+
else
|
137
|
+
code.gsub("`", "")
|
138
|
+
end
|
139
|
+
end
|
123
140
|
end
|
124
141
|
end
|
@@ -49,8 +49,8 @@ module Boxcars
|
|
49
49
|
[:answer_box, :snippet_highlighted_words, 0],
|
50
50
|
%i[sports_results game_spotlight],
|
51
51
|
%i[knowledge_graph description],
|
52
|
-
[:organic_results, 0, :
|
53
|
-
[:organic_results, 0, :
|
52
|
+
[:organic_results, 0, :snippet],
|
53
|
+
[:organic_results, 0, :snippet_highlighted_words, 0]
|
54
54
|
].freeze
|
55
55
|
|
56
56
|
def find_answer(res)
|
data/lib/boxcars/boxcar/sql.rb
CHANGED
@@ -20,6 +20,8 @@ module Boxcars
|
|
20
20
|
kwargs[:name] ||= "Database"
|
21
21
|
kwargs[:description] ||= format(SQLDESC, name: name)
|
22
22
|
kwargs[:prompt] ||= my_prompt
|
23
|
+
kwargs[:stop] ||= ["SQLResult:"]
|
24
|
+
|
23
25
|
super(**kwargs)
|
24
26
|
end
|
25
27
|
|
@@ -73,6 +75,7 @@ module Boxcars
|
|
73
75
|
|
74
76
|
def get_embedded_sql_answer(text)
|
75
77
|
code = text[/^SQLQuery: (.*)/, 1]
|
78
|
+
code = extract_code text.split('SQLQuery:').last.strip
|
76
79
|
Boxcars.debug code, :yellow
|
77
80
|
output = clean_up_output(connection.exec_query(code))
|
78
81
|
Result.new(status: :ok, answer: output, explanation: "Answer: #{output.to_json}", code: code)
|
@@ -87,7 +90,8 @@ module Boxcars
|
|
87
90
|
when /^Answer:/
|
88
91
|
Result.from_text(text)
|
89
92
|
else
|
90
|
-
Result.from_error("
|
93
|
+
Result.from_error("Your answer wasn't formatted properly - try again. I expected your answer to " \
|
94
|
+
"start with \"SQLQuery:\".")
|
91
95
|
end
|
92
96
|
end
|
93
97
|
|
@@ -99,8 +103,8 @@ module Boxcars
|
|
99
103
|
"to return the most interesting examples in the database.\n",
|
100
104
|
"Never query for all the columns from a specific table, only ask for the elevant columns given the question.\n",
|
101
105
|
"Pay attention to use only the column names that you can see in the schema description. Be careful to ",
|
102
|
-
"not query for columns that do not exist. Also, pay attention to which column is in which table
|
103
|
-
|
106
|
+
"not query for columns that do not exist. Also, pay attention to which column is in which table.\n",
|
107
|
+
"Use the following format:\n",
|
104
108
|
"Question: 'Question here'\n",
|
105
109
|
"SQLQuery: 'SQL Query to run'\n",
|
106
110
|
"SQLResult: 'Result of the SQLQuery'\n",
|
@@ -49,11 +49,15 @@ module Boxcars
|
|
49
49
|
else
|
50
50
|
# the thought should be the frist line here if it doesn't start with "Action:"
|
51
51
|
thought = engine_output.split(/\n+/).reject(&:empty?).first
|
52
|
-
Boxcars.debug("
|
53
|
-
regex = /Action: (?<action
|
52
|
+
Boxcars.debug("Thought: #{thought}", :yellow)
|
53
|
+
regex = /Action(?<extra>[\s\d]*): (?<action>.+?)\n+Action Input:(?<action_input>.+)/m
|
54
54
|
match = regex.match(engine_output)
|
55
|
-
|
56
|
-
|
55
|
+
|
56
|
+
# we have an unexpected output from the engine
|
57
|
+
unless match
|
58
|
+
return [:error, "You gave me an improperly fomatted answer - try again. For example, if you know the final anwwer, " \
|
59
|
+
"start with #{FINAL_ANSWER_ACTION.inspect}"]
|
60
|
+
end
|
57
61
|
|
58
62
|
action = match[:action].strip
|
59
63
|
action_input = match[:action_input].strip.delete_prefix('"').delete_suffix('"')
|
@@ -63,24 +67,25 @@ module Boxcars
|
|
63
67
|
|
64
68
|
CTEMPLATE = [
|
65
69
|
syst("Answer the following questions as best you can. You have access to the following actions:\n",
|
66
|
-
"%<boxcar_descriptions>s"
|
67
|
-
|
70
|
+
"%<boxcar_descriptions>s\n",
|
71
|
+
"Use the following format:\n",
|
68
72
|
"Question: the input question you must answer\n",
|
69
73
|
"Thought: you should always think about what to do\n",
|
70
|
-
"Action: the action to take, should be one
|
74
|
+
"Action: the action to take, should be one from this list: %<boxcar_names>s\n",
|
71
75
|
"Action Input: the input to the action\n",
|
72
76
|
"Observation: the result of the action\n",
|
73
77
|
"... (this Thought/Action/Action Input/Observation sequence can repeat N times)\n",
|
74
|
-
"Thought: I
|
78
|
+
"Thought: I know the final answer\n",
|
75
79
|
"Final Answer: the final answer to the original input question\n",
|
76
|
-
"Next Actions:
|
80
|
+
"Next Actions: Up to 3 logical suggested next questions for the user to ask after getting this answer.\n",
|
81
|
+
"Remember to start a line with \"Final Answer:\" to give me the final answer.\n",
|
77
82
|
"Begin!"),
|
78
83
|
user("Question: %<input>s"),
|
79
84
|
assi("Thought: %<agent_scratchpad>s")
|
80
85
|
].freeze
|
81
86
|
|
82
87
|
def boxcar_names
|
83
|
-
@boxcar_names ||= boxcars.map(&:name)
|
88
|
+
@boxcar_names ||= "[#{boxcars.map(&:name).join(', ')}]"
|
84
89
|
end
|
85
90
|
|
86
91
|
def boxcar_descriptions
|
data/lib/boxcars/train.rb
CHANGED
@@ -27,6 +27,7 @@ module Boxcars
|
|
27
27
|
# Extract the boxcar name and input from the text.
|
28
28
|
# @param text [String] The text to extract from.
|
29
29
|
def extract_boxcar_and_input(text)
|
30
|
+
Result.new(status: :ok, answer: text, explanation: engine_output)
|
30
31
|
end
|
31
32
|
|
32
33
|
# build the scratchpad for the engine
|
@@ -56,6 +57,7 @@ module Boxcars
|
|
56
57
|
end
|
57
58
|
if parsed_output.is_a?(Result)
|
58
59
|
TrainAction.from_result(boxcar: "Final Answer", result: parsed_output, log: full_output)
|
60
|
+
# elsif parsed_output[0] == "Error"
|
59
61
|
else
|
60
62
|
TrainAction.new(boxcar: parsed_output[0], boxcar_input: parsed_output[1], log: full_output)
|
61
63
|
end
|
@@ -194,10 +196,15 @@ module Boxcars
|
|
194
196
|
begin
|
195
197
|
observation = boxcar.run(output.boxcar_input)
|
196
198
|
return_direct = boxcar.return_direct
|
199
|
+
rescue Boxcars::ConfigurationError, Boxcars::SecurityError => e
|
200
|
+
raise e
|
197
201
|
rescue StandardError => e
|
198
202
|
Boxcars.error "Error in #{boxcar.name} boxcar#call: #{e}", :red
|
199
203
|
observation = "Error - #{e}, correct and try again."
|
200
204
|
end
|
205
|
+
elsif output.boxcar == :error
|
206
|
+
observation = output.log
|
207
|
+
return_direct = false
|
201
208
|
else
|
202
209
|
observation = "#{output.boxcar} is not a valid boxcar, try another one."
|
203
210
|
return_direct = false
|
data/lib/boxcars/version.rb
CHANGED
data/lib/boxcars.rb
CHANGED
@@ -25,12 +25,13 @@ module Boxcars
|
|
25
25
|
# Configuration contains gem settings
|
26
26
|
class Configuration
|
27
27
|
attr_writer :openai_access_token, :serpapi_api_key
|
28
|
-
attr_accessor :organization_id, :logger, :log_prompts, :default_train, :default_engine
|
28
|
+
attr_accessor :organization_id, :logger, :log_prompts, :log_generated, :default_train, :default_engine
|
29
29
|
|
30
30
|
def initialize
|
31
31
|
@organization_id = nil
|
32
32
|
@logger = Rails.logger if defined?(Rails)
|
33
33
|
@log_prompts = ENV.fetch("LOG_PROMPTS", false)
|
34
|
+
@log_generated = ENV.fetch("LOG_GEN", false)
|
34
35
|
end
|
35
36
|
|
36
37
|
# @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.2.
|
4
|
+
version: 0.2.4
|
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-
|
12
|
+
date: 2023-03-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: debug
|