boxcars 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d5ae0de1aba4038723912365d6ac1d50da0e34a40aad508130ecc86e71f91de
4
- data.tar.gz: e0430621516358a59b7eeaadfa44fe78eed0b3ef92d929c264435d0946dbce5e
3
+ metadata.gz: 8eb0adb30464688c5a68391ffb19a5d08188f87283d7cf3de28b12a30b927971
4
+ data.tar.gz: 94605b14f7974159d21eb2cf219b8d4695533761084fe784419e47a04843c6c2
5
5
  SHA512:
6
- metadata.gz: a054ad6b3b3caef1c6bb39fbd9a667779c4dc638800e905b717285b8f5dde4a578e3325373176b099af9f4f7d07b6f7803f87fe67c4f771bfce8894ef209188e
7
- data.tar.gz: f3a3020bd0c393c25cd430b8702e26a7a39b87127372787c416042da63c6fb90826773ca81a456ba67a1add908790620757d8b9aab4db32269e3391d576c5ea5
6
+ metadata.gz: 4b92e4e8c98ada38bb4acf5ed5f0bd563bcfe2ab29d9781002a585799aba35cfa82992086484886563585ad0b7a9795691f9804ef4807b58aaa29c8bea88a761
7
+ data.tar.gz: e46f9a26fad0b0eb339868daef5bd4c05d750af08277f83b4edb15839a712553584223f056dc2aa403fccb8b5292a6ea57aadf12c04595f909d561f1fbbe2995
data/CHANGELOG.md CHANGED
@@ -1,12 +1,29 @@
1
1
  # Changelog
2
2
 
3
- ## [Unreleased](https://github.com/BoxcarsAI/boxcars/tree/HEAD)
3
+ ## [v0.1.4](https://github.com/BoxcarsAI/boxcars/tree/v0.1.4) (2023-02-22)
4
4
 
5
- [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.2...HEAD)
5
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.3...v0.1.4)
6
+
7
+ **Implemented enhancements:**
8
+
9
+ - Extend Sql concept to produce and run ActiveRecord code instead of SQL [\#9](https://github.com/BoxcarsAI/boxcars/issues/9)
10
+
11
+ **Merged pull requests:**
12
+
13
+ - first pass at an ActiveRecord boxcar [\#18](https://github.com/BoxcarsAI/boxcars/pull/18) ([francis](https://github.com/francis))
14
+ - change Boxcars::default\_train to Boxcars::train to improve code reada… [\#17](https://github.com/BoxcarsAI/boxcars/pull/17) ([francis](https://github.com/francis))
15
+ - rename class Serp to GoogleSearch [\#16](https://github.com/BoxcarsAI/boxcars/pull/16) ([francis](https://github.com/francis))
16
+ - Update README.md [\#15](https://github.com/BoxcarsAI/boxcars/pull/15) ([tabrez-syed](https://github.com/tabrez-syed))
17
+
18
+ ## [v0.1.3](https://github.com/BoxcarsAI/boxcars/tree/v0.1.3) (2023-02-17)
19
+
20
+ [Full Changelog](https://github.com/BoxcarsAI/boxcars/compare/v0.1.2...v0.1.3)
6
21
 
7
22
  **Closed issues:**
8
23
 
24
+ - generate changelog automatically [\#12](https://github.com/BoxcarsAI/boxcars/issues/12)
9
25
  - Make sure the yard docs are up to date and have coverage [\#7](https://github.com/BoxcarsAI/boxcars/issues/7)
26
+ - Name changes and code movement. [\#6](https://github.com/BoxcarsAI/boxcars/issues/6)
10
27
  - Specs need environment variables to be set to run green [\#4](https://github.com/BoxcarsAI/boxcars/issues/4)
11
28
 
12
29
  **Merged pull requests:**
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.1.3)
4
+ boxcars (0.1.5)
5
5
  google_search_results (~> 2.2)
6
6
  ruby-openai (~> 3.0)
7
7
 
data/README.md CHANGED
@@ -1,15 +1,26 @@
1
- # Boxcars
1
+ <h2 align="center">Boxcars</h2>
2
2
 
3
- This gem lets you compose new systems with composability using systems like OpenAI, Search, and SQL (and many more).
3
+ <h4 align="center">
4
+ <a href="https://www.boxcars.ai">Website</a> |
5
+ <a href="https://www.boxcars.ai/roadmap">Roadmap</a> |
6
+ <a href="https://www.boxcars.ai/blog">Blog</a> |
7
+ <a href="https://github.com/BoxcarsAI/boxcars/wiki">Documentation</a>
8
+ </h4>
4
9
 
5
- The popular python library langchain is a precursor to this work, but we wanted to put a ruby spin on things and make it easier to get started.
10
+ <p align="center">
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
+ </p>
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.(including your concepts).
15
+
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.
6
17
 
7
18
  ## Concepts
8
19
  All of these concepts are in a module named Boxcars:
9
- - Prompt: a prompt is used by an Engine to generate text results.
10
- - Engine: an entity that generates text from a Prompt.
11
- - Boxcar: an encapsulation that does one thing (search, math, SQL, etc) and a many use an Engine to get their work accomplished.cc
12
- - Train: given a list of Boxcars and an Engine, an answer if found by breaking the promlem into peices for an indvidual Boxcar to solve. This is all joined back together to yield a final result. There is currently only one implementation - ZeroShot. You can construct it directly, or just use `Boxcars::default_train`
20
+ - Prompt: used by an Engine to generate text results.
21
+ - Engine: an entity that generates text from a Prompt. OpenAI's LLM text generatory is the default Engine if no other is specified.
22
+ - Boxcar: an encapsulation of a concept that performs something of interest (such as search, math, or SQL). A can use an Engine to do its work.
23
+ - Train: Given a list of Boxcars and an optionally an Engine, a Train breaks down a problem into pieces for individual Boxcars to solve. The individual results are then combined until a final answer is found. ZeroShot is the only current implementation of Train, and you can either construct it directly or use `Boxcars::train` when you want to build a Train.
13
24
 
14
25
  ## Installation
15
26
 
@@ -29,7 +40,7 @@ Or install it yourself as:
29
40
 
30
41
  ## Usage
31
42
 
32
- We will document many more examples soon, but here are a couple. The first step is to setup your environment variables for OpenAI and Serp (OPENAI_ACCESS_TOKEN, SERPAPI_API_KEY). If you don't want to set them in your environment, they can be passed in as well to the API.
43
+ We will be adding more examples soon, but here are a couple to get you started. First, you'll need to set up your environment variables for OpenAI and Google SERP (OPENAI_ACCESS_TOKEN, SERPAPI_API_KEY). If you prefer not to set these variables in your environment, you can pass them directly into the API.
33
44
 
34
45
  In the examples below, we added one rubygem to load the environment at the first line, but depending on what you want, you might not need this.
35
46
  ```ruby
@@ -37,6 +48,11 @@ require "dotenv/load"
37
48
  require "boxcars"
38
49
  ```
39
50
 
51
+ Note: if you want to try out the examples below, run this command and then paste in the code segments of interest:
52
+ ```bash
53
+ irb -r dotenv/load -r boxcars
54
+ ```
55
+
40
56
  ### Direct Boxcar Use
41
57
 
42
58
  ```ruby
@@ -45,7 +61,7 @@ engine = Boxcars::Openai.new(max_tokens: 256)
45
61
  calc = Boxcars::Calculator.new(engine: engine)
46
62
  puts calc.run "what is pi to the forth power divided by 22.1?"
47
63
  ```
48
- This segment above (try it by pasting into an `irb` session)
64
+ Produces:
49
65
  ```text
50
66
  > Entering Calculator#run
51
67
  what is pi to the forth power divided by 22.1?
@@ -63,10 +79,11 @@ Note that since Openai is currently the most used Engine, if you do not pass in
63
79
  calc = Boxcars::Calculator.new # just use the default Engine
64
80
  puts calc.run "what is pi to the forth power divided by 22.1?"
65
81
  ```
82
+ You can change the default_engine with `Boxcars::configuration.default_engine = NewDefaultEngine`
66
83
  ### Boxcars currently implemmented
67
84
 
68
85
  Here is what we have so far, but please put up a PR with your new ideas.
69
- - Search: uses the SERP API to do seaches
86
+ - GoogleSearch: uses the SERP API to do seaches
70
87
  - Calculator: uses an Engine to generate ruby code to do math
71
88
  - SQL: given an ActiveRecord connection, it will generate and run sql statments from a prompt.
72
89
 
@@ -74,10 +91,10 @@ Here is what we have so far, but please put up a PR with your new ideas.
74
91
  ```ruby
75
92
  # run a Train for a calculator, and search using default Engine
76
93
  boxcars = [Boxcars::Calculator.new, Boxcars::Serp.new]
77
- train = Boxcars.default_train.new(boxcars: boxcars)
94
+ train = Boxcars.train.new(boxcars: boxcars)
78
95
  puts train.run "What is pi times the square root of the average temperature in Austin TX in January?"
79
96
  ```
80
- This outputs:
97
+ Produces:
81
98
  ```text
82
99
  > Entering Zero Shot#run
83
100
  What is pi times the square root of the average temperature in Austin TX in January?
data/boxcars.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Francis Sullivan", "Tabrez Syed"]
9
9
  spec.email = ["hi@boxcars.ai"]
10
10
 
11
- spec.summary = "Boxcars provide an API to connect together Boxcars and then conduct them. Inspired by python langchain."
12
- spec.description = "You simply give a number of boxcars to a train, and it does the magic."
11
+ spec.summary = "Boxcars is a gem that enables you to create new systems with AI composability. Inspired by python langchain."
12
+ spec.description = "You simply set an OpenAI key, give a number of Boxcars to a Train, and magic ensues when you run it."
13
13
  spec.homepage = "https://github.com/BoxcarsAI/boxcars"
14
14
  spec.license = "MIT"
15
15
  spec.required_ruby_version = ">= 2.6.0"
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
23
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
24
24
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
25
  `git ls-files -z`.split("\x0").reject do |f|
26
- (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
26
+ (f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features|notebooks)/|\.(?:git|travis|circleci)|appveyor)})
27
27
  end
28
28
  end
29
29
  spec.bindir = "exe"
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Boxcars is a framework for running a series of tools to get an answer to a question.
4
+ module Boxcars
5
+ # A Boxcar that interprets a prompt and executes SQL code to get answers
6
+ class ActiveRecord < EngineBoxcar
7
+ # the description of this engine boxcar
8
+ ARDESC = "useful for when you need to query a database for an application named %<name>s."
9
+ LOCKED_OUT_MODELS = %w[ActiveRecord::SchemaMigration ActiveRecord::InternalMetadata ApplicationRecord].freeze
10
+ attr_accessor :connection, :input_key, :requested_models, :read_only
11
+ attr_reader :except_models
12
+
13
+ # @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
14
+ # @param models [Array<ActiveRecord::Model>] The models to use for this boxcar. Will use all if nil.
15
+ # @param read_only [Boolean] Whether to use read only models. Defaults to true.
16
+ # @param kwargs [Hash] Any other keyword arguments. These can include:
17
+ # :name, :description, :prompt, :input_key, :output_key and :except_models
18
+ def initialize(engine: nil, models: nil, read_only: true, **kwargs)
19
+ check_models(models)
20
+ @except_models = LOCKED_OUT_MODELS + kwargs[:except_models].to_a
21
+ @read_only = read_only
22
+ @input_key = kwargs[:input_key] || :question
23
+ @output_key = kwargs[:output_key] || :answer
24
+ the_prompt = kwargs[prompt] || my_prompt
25
+ name = kwargs[:name] || "Data"
26
+ super(name: name,
27
+ description: kwargs[:description] || format(ARDESC, name: name),
28
+ engine: engine,
29
+ prompt: the_prompt,
30
+ output_key: output_key)
31
+ end
32
+
33
+ # the input keys for the prompt
34
+ # @return [Array<Symbol>] The input keys for the prompt.
35
+ def input_keys
36
+ [input_key]
37
+ end
38
+
39
+ # the output keys for the prompt
40
+ # @return [Array<Symbol>] The output keys for the prompt.
41
+ def output_keys
42
+ [output_key]
43
+ end
44
+
45
+ # call the boxcar
46
+ # @param inputs [Hash] The inputs to the boxcar.
47
+ # @return [Hash] The outputs from the boxcar.
48
+ def call(inputs:)
49
+ t = predict(question: inputs[input_key], top_k: 5, model_info: model_info, stop: ["Answer:"]).strip
50
+ answer = get_answer(t)
51
+ puts answer.colorize(:magenta)
52
+ { output_key => answer }
53
+ end
54
+
55
+ private
56
+
57
+ def read_only?
58
+ read_only
59
+ end
60
+
61
+ def check_models(models)
62
+ if models.is_a?(Array) && models.length.positive?
63
+ @requested_models = models
64
+ models.each do |m|
65
+ raise ArgumentError, "model #{m} needs to be an Active Record model" unless m.ancestors.include?(::ActiveRecord::Base)
66
+ end
67
+ elsif models
68
+ raise ArgumentError, "models needs to be an array of Active Record models"
69
+ end
70
+ end
71
+
72
+ def wanted_models
73
+ the_models = requested_models || ::ActiveRecord::Base.descendants
74
+ the_models.reject { |m| except_models.include?(m.name) }
75
+ end
76
+
77
+ def models
78
+ models = wanted_models.map(&:name)
79
+ models.join(", ")
80
+ end
81
+
82
+ def model_info
83
+ models = wanted_models
84
+ models.pretty_inspect
85
+ end
86
+
87
+ # to be safe, we wrap the code in a transaction and rollback
88
+ # rubocop:disable Lint/SuppressedException
89
+ def wrap_in_transaction
90
+ ::ActiveRecord::Base.transaction do
91
+ yield
92
+ ensure
93
+ raise ::ActiveRecord::Rollback
94
+ end
95
+ rescue ::ActiveRecord::Rollback
96
+ end
97
+ # rubocop:enable Lint/SuppressedException
98
+
99
+ def safe_to_run?(code)
100
+ return true unless read_only?
101
+
102
+ bad_words = %w[delete delete_all destroy destroy_all update update_all upsert upsert_all create save insert drop alter
103
+ truncate revoke commit rollback reset execute].freeze
104
+ without_strings = code.gsub(/('([^'\\]*(\\.[^'\\]*)*)'|"([^"\\]*(\\.[^"\\]*)*"))/, 'XX')
105
+ word_list = without_strings.split(/[.,()]/)
106
+
107
+ bad_words.each do |w|
108
+ if word_list.include?(w)
109
+ puts "code included destructive instruction: #{w} #{code}"
110
+ return false
111
+ end
112
+ end
113
+
114
+ true
115
+ end
116
+
117
+ def get_active_record_answer(text)
118
+ code = text[/^ARCode: (.*)/, 1]
119
+ puts code.colorize(:yellow)
120
+ raise SecurityError, "Can not run code that makes changes in read-only mode" unless safe_to_run?(code)
121
+
122
+ # rubocop:disable Security/Eval
123
+ output = eval code
124
+ # rubocop:enable Security/Eval
125
+ output = 0 if output.is_a?(Array) && output.empty?
126
+ output = output.first if output.is_a?(Array) && output.length == 1
127
+ "Answer: #{output.inspect}"
128
+ rescue StandardError => e
129
+ "Error: #{e.message}"
130
+ end
131
+
132
+ def get_answer(text)
133
+ case text
134
+ when /^ARCode:/
135
+ get_active_record_answer(text)
136
+ when /^Answer:/
137
+ text
138
+ else
139
+ raise Boxcars::Error "Unknown format from engine: #{text}"
140
+ end
141
+ end
142
+
143
+ TEMPLATE = <<~IPT
144
+ Given an input question, first create a syntactically correct Rails Active Record code to run,
145
+ then look at the results of the code and return the answer. Unless the user specifies
146
+ in her question a specific number of examples she wishes to obtain, limit your code
147
+ to at most %<top_k>s results.
148
+
149
+ Never query for all the columns from a specific model, only ask for a the few relevant attributes given the question.
150
+
151
+ Pay attention to use only the attribute names that you can see in the model description. Be careful to not query for attributes that do not exist.
152
+ Also, pay attention to which attribute is in which model.
153
+
154
+ Use the following format:
155
+ Question: "Question here"
156
+ ARCode: "Active Record code to run"
157
+ Answer: "Final answer here"
158
+
159
+ Only use the following Active Record models:
160
+ %<model_info>s
161
+
162
+ Question: %<question>s
163
+ IPT
164
+
165
+ # The prompt to use for the engine.
166
+ def my_prompt
167
+ @my_prompt ||= Prompt.new(input_variables: [:question, :top_k, :model_info], template: TEMPLATE)
168
+ end
169
+ end
170
+ end
@@ -13,7 +13,7 @@ module Boxcars
13
13
  # @param engine [Boxcars::Engine] The engine to user for this boxcar. Can be inherited from a train if nil.
14
14
  def initialize(prompt:, engine: nil, output_key: "text", name: nil, description: nil)
15
15
  @prompt = prompt
16
- @engine = engine || Boxcars.default_engine.new
16
+ @engine = engine || Boxcars.engine.new
17
17
  @output_key = output_key
18
18
  super(name: name, description: description)
19
19
  end
@@ -2,8 +2,9 @@
2
2
 
3
3
  require 'google_search_results'
4
4
  module Boxcars
5
- # A Boxcar that uses the Google SerpAPI to get answers to questions.
6
- class Serp < Boxcar
5
+ # A Boxcar that uses the Google SERP API to get answers to questions.
6
+ # It looks through SERP (search engine results page) results to find the answer.
7
+ class GoogleSearch < Boxcar
7
8
  # the description of this boxcar
8
9
  SERPDESC = "useful for when you need to answer questions about current events." \
9
10
  "You should ask targeted questions"
@@ -15,14 +16,14 @@ module Boxcars
15
16
  def initialize(name: "Search", description: SERPDESC, serpapi_api_key: "not set")
16
17
  super(name: name, description: description)
17
18
  api_key = Boxcars.configuration.serpapi_api_key(serpapi_api_key: serpapi_api_key)
18
- GoogleSearch.api_key = api_key
19
+ ::GoogleSearch.api_key = api_key
19
20
  end
20
21
 
21
22
  # Get an answer from Google using the SerpAPI.
22
23
  # @param question [String] The question to ask Google.
23
24
  # @return [String] The answer to the question.
24
25
  def run(question)
25
- search = GoogleSearch.new(q: question)
26
+ search = ::GoogleSearch.new(q: question)
26
27
  rv = find_answer(search.get_hash)
27
28
  puts "Question: #{question}"
28
29
  puts "Answer: #{rv}"
@@ -33,7 +34,7 @@ module Boxcars
33
34
  # @param question [String] The question to ask Google.
34
35
  # @return [String] The location found.
35
36
  def get_location(question)
36
- search = GoogleSearch.new(q: question, limit: 3)
37
+ search = ::GoogleSearch.new(q: question, limit: 3)
37
38
  rv = search.get_location
38
39
  puts "Question: #{question}"
39
40
  puts "Answer: #{rv}"
@@ -5,7 +5,7 @@ module Boxcars
5
5
  # A Boxcar that interprets a prompt and executes SQL code to get answers
6
6
  class SQL < EngineBoxcar
7
7
  # the description of this engine boxcar
8
- SQLDESC = "useful for when you need to query a SQL database"
8
+ SQLDESC = "useful for when you need to query a database for %<name>s."
9
9
  attr_accessor :connection, :input_key
10
10
 
11
11
  # @param connection [ActiveRecord::Connection] The SQL connection to use for this boxcar.
@@ -14,12 +14,13 @@ module Boxcars
14
14
  # @param output_key [Symbol] The key to use for the output. Defaults to :answer.
15
15
  # @param kwargs [Hash] Any other keyword arguments to pass to the parent class. This can include
16
16
  # :name, :description and :prompt
17
- def initialize(connection:, engine: nil, input_key: :question, output_key: :answer, **kwargs)
18
- @connection = connection
17
+ def initialize(connection: nil, engine: nil, input_key: :question, output_key: :answer, **kwargs)
18
+ @connection = connection || ::ActiveRecord::Base.connection
19
19
  @input_key = input_key
20
20
  the_prompt = kwargs[prompt] || my_prompt
21
- super(name: kwargs[:name] || "SQLdatabase",
22
- description: kwargs[:description] || SQLDESC,
21
+ name = kwargs[:name] || "data"
22
+ super(name: name,
23
+ description: kwargs[:description] || format(SQLDESC, name: name),
23
24
  engine: engine,
24
25
  prompt: the_prompt,
25
26
  output_key: output_key)
@@ -73,7 +74,6 @@ module Boxcars
73
74
  code = text[/^SQLQuery: (.*)/, 1]
74
75
  puts code.colorize(:yellow)
75
76
  output = connection.exec_query(code).to_a
76
- puts "Answer: #{output}"
77
77
  "Answer: #{output}"
78
78
  end
79
79
 
@@ -116,18 +116,5 @@ module Boxcars
116
116
  def my_prompt
117
117
  @my_prompt ||= Prompt.new(input_variables: [:question, :dialect, :top_k], template: TEMPLATE)
118
118
  end
119
-
120
- # DECIDER_TEMPLATE = <<~DPT
121
- # Given the below input question and list of potential tables, output a comma separated list of the table names that may
122
- # be necessary to answer this question.
123
- # Question: %<query>s
124
- # Table Names: %<table_names>s
125
- # Relevant Table Names:
126
- # DPT
127
- # DECIDER_PROMPT = Prompt.new(
128
- # input_variables: %i[query table_names],
129
- # template: DECIDER_TEMPLATE,
130
- # output_parser: CommaSeparatedListOutputParser
131
- # )
132
119
  end
133
120
  end
@@ -116,5 +116,6 @@ end
116
116
 
117
117
  require "boxcars/boxcar/engine_boxcar"
118
118
  require "boxcars/boxcar/calculator"
119
- require "boxcars/boxcar/serp"
119
+ require "boxcars/boxcar/google_search"
120
120
  require "boxcars/boxcar/sql"
121
+ require "boxcars/boxcar/active_record"
@@ -33,14 +33,15 @@ module Boxcars
33
33
  # @param engine [Boxcars::Engine] The engine to use for this train.
34
34
  # @param name [String] The name of the train. Defaults to 'Zero Shot'.
35
35
  # @param description [String] The description of the train. Defaults to 'Zero Shot Train'.
36
- def initialize(boxcars:, engine: nil, name: 'Zero Shot', description: 'Zero Shot Train')
36
+ # @param prompt [Boxcars::Prompt] The prompt to use. Defaults to the built-in prompt.
37
+ def initialize(boxcars:, engine: nil, name: 'Zero Shot', description: 'Zero Shot Train', prompt: nil)
37
38
  @observation_prefix = 'Observation: '
38
39
  @engine_prefix = 'Thought:'
39
- prompt = self.class.create_prompt(boxcars: boxcars)
40
+ prompt ||= self.class.create_prompt(boxcars: boxcars)
40
41
  super(engine: engine, boxcars: boxcars, prompt: prompt, name: name, description: description)
41
42
  end
42
43
 
43
- # Create prompt in the style of the zero shot agent.
44
+ # Create prompt in the style of the zero shot agent. Without arguments, returns the default prompt.
44
45
  # @param boxcars [Array<Boxcars::Boxcar>] List of boxcars the agent will have access to, used to format the prompt.
45
46
  # @param prefix [String] String to put before the main prompt.
46
47
  # @param suffix [String] String to put after the main prompt.
data/lib/boxcars/train.rb CHANGED
@@ -205,7 +205,7 @@ module Boxcars
205
205
  observation = "#{output.boxcar} is not a valid boxcar, try another one."
206
206
  return_direct = false
207
207
  end
208
- puts "#Observation: #{observation}".colorize(:green)
208
+ puts "Observation: #{observation}".colorize(:green)
209
209
  intermediate_steps.append([output, observation])
210
210
  if return_direct
211
211
  output = TrainFinish.new({ return_values[0] => observation }, "")
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.1.3"
5
+ VERSION = "0.1.5"
6
6
  end
data/lib/boxcars.rb CHANGED
@@ -16,6 +16,9 @@ module Boxcars
16
16
  # Error class for all Boxcars value errors.
17
17
  class ValueError < Error; end
18
18
 
19
+ # Error class for all Boxcars security errors.
20
+ class SecurityError < Error; end
21
+
19
22
  # simple string colorization
20
23
  class ::String
21
24
  # colorize a string
@@ -36,7 +39,7 @@ module Boxcars
36
39
  # Configuration contains gem settings
37
40
  class Configuration
38
41
  attr_writer :openai_access_token, :serpapi_api_key
39
- attr_accessor :organization_id, :logger, :log_prompts
42
+ attr_accessor :organization_id, :logger, :log_prompts, :default_train, :default_engine
40
43
 
41
44
  def initialize
42
45
  @organization_id = nil
@@ -96,13 +99,13 @@ module Boxcars
96
99
  end
97
100
 
98
101
  # Return the default Train class.
99
- def self.default_train
100
- Boxcars::ZeroShot
102
+ def self.train
103
+ configuration.default_train || Boxcars::ZeroShot
101
104
  end
102
105
 
103
106
  # Return the default Engine class.
104
- def self.default_engine
105
- Boxcars::Openai
107
+ def self.engine
108
+ configuration.default_engine || Boxcars::Openai
106
109
  end
107
110
  end
108
111
 
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.3
4
+ version: 0.1.5
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-17 00:00:00.000000000 Z
12
+ date: 2023-02-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: debug
@@ -81,7 +81,8 @@ dependencies:
81
81
  - - "~>"
82
82
  - !ruby/object:Gem::Version
83
83
  version: '3.0'
84
- description: You simply give a number of boxcars to a train, and it does the magic.
84
+ description: You simply set an OpenAI key, give a number of Boxcars to a Train, and
85
+ magic ensues when you run it.
85
86
  email:
86
87
  - hi@boxcars.ai
87
88
  executables: []
@@ -102,9 +103,10 @@ files:
102
103
  - boxcars.gemspec
103
104
  - lib/boxcars.rb
104
105
  - lib/boxcars/boxcar.rb
106
+ - lib/boxcars/boxcar/active_record.rb
105
107
  - lib/boxcars/boxcar/calculator.rb
106
108
  - lib/boxcars/boxcar/engine_boxcar.rb
107
- - lib/boxcars/boxcar/serp.rb
109
+ - lib/boxcars/boxcar/google_search.rb
108
110
  - lib/boxcars/boxcar/sql.rb
109
111
  - lib/boxcars/engine.rb
110
112
  - lib/boxcars/engine/engine_result.rb
@@ -143,6 +145,6 @@ requirements: []
143
145
  rubygems_version: 3.2.32
144
146
  signing_key:
145
147
  specification_version: 4
146
- summary: Boxcars provide an API to connect together Boxcars and then conduct them.
148
+ summary: Boxcars is a gem that enables you to create new systems with AI composability.
147
149
  Inspired by python langchain.
148
150
  test_files: []