boxcars 0.7.4 → 0.7.5

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: b7d7e68a8fe277fba9e416c7f582ee60135ef79f101da5f8da802a900330e807
4
- data.tar.gz: 7f7e7f5243dc3a3f646dee5475456b9df640773e6411053b8f8514a5b9ef95be
3
+ metadata.gz: fba0b8f234c11e72583e1058f76d4d29116dd76d34e59cb6337f242a16ce1b90
4
+ data.tar.gz: e3b2a7f524934c3ba6271eb5530012659c2fa9e03326b23f2105c4cc15fc8966
5
5
  SHA512:
6
- metadata.gz: 91af273bb15b972e59d0c1c2f142e19fbfc226298ce650da55e7925054e3c9ea2076f2c7ca9e741b2280cea33a913be27bf7f65681d61f6fbfa02d8361726e00
7
- data.tar.gz: e4f6d515b34bc9ba1b12b70f7cd0813930b825675b93d263e991858d8c774ffc2030ce27264aac3c458f921fede365651a8344c1a4f279852b0c73c30052e39b
6
+ metadata.gz: 4f0a6d64dbcfb79dadefd3ffad4ac318617d985fee5f57eb40338338edfeb3e4815266665884dd00544d95e215ef20f8d431113933532a75f9f9be6104c216e5
7
+ data.tar.gz: 9a123e55156fabf642dd69c0eec7d544d54b9cd80d0a1dd661189cafe406560aa115195b376db0654fb873a71c7f397ceb6572907786c34cbeb546ad31d26447
data/.rubocop.yml CHANGED
@@ -1,7 +1,10 @@
1
1
  require:
2
- - rubocop-rspec
3
2
  - rubocop-rake
4
3
 
4
+ plugins:
5
+ - rubocop-rspec
6
+
7
+
5
8
  AllCops:
6
9
  TargetRubyVersion: 3
7
10
  Exclude:
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.7.4)
4
+ boxcars (0.7.5)
5
5
  google_search_results (~> 2.2)
6
6
  gpt4all (~> 0.0.5)
7
7
  hnswlib (~> 0.9)
@@ -58,7 +58,7 @@ GEM
58
58
  benchmark (0.4.0)
59
59
  bigdecimal (3.1.9)
60
60
  concurrent-ruby (1.3.5)
61
- connection_pool (2.5.0)
61
+ connection_pool (2.5.1)
62
62
  console (1.30.2)
63
63
  fiber-annotation
64
64
  fiber-local (~> 1.1)
@@ -91,7 +91,7 @@ GEM
91
91
  fiber-annotation (0.2.0)
92
92
  fiber-local (1.1.0)
93
93
  fiber-storage
94
- fiber-storage (1.0.0)
94
+ fiber-storage (1.0.1)
95
95
  github_changelog_generator (1.16.4)
96
96
  activesupport
97
97
  async (>= 1.25.0)
@@ -131,7 +131,7 @@ GEM
131
131
  mime-types (3.6.2)
132
132
  logger
133
133
  mime-types-data (~> 3.2015)
134
- mime-types-data (3.2025.0408)
134
+ mime-types-data (3.2025.0415)
135
135
  minitest (5.25.5)
136
136
  multi_json (1.15.0)
137
137
  multipart-post (2.4.1)
@@ -139,27 +139,27 @@ GEM
139
139
  uri
140
140
  netrc (0.11.0)
141
141
  nio4r (2.7.4)
142
- nokogiri (1.18.7-aarch64-linux-gnu)
142
+ nokogiri (1.18.8-aarch64-linux-gnu)
143
143
  racc (~> 1.4)
144
- nokogiri (1.18.7-aarch64-linux-musl)
144
+ nokogiri (1.18.8-aarch64-linux-musl)
145
145
  racc (~> 1.4)
146
- nokogiri (1.18.7-arm-linux-gnu)
146
+ nokogiri (1.18.8-arm-linux-gnu)
147
147
  racc (~> 1.4)
148
- nokogiri (1.18.7-arm-linux-musl)
148
+ nokogiri (1.18.8-arm-linux-musl)
149
149
  racc (~> 1.4)
150
- nokogiri (1.18.7-arm64-darwin)
150
+ nokogiri (1.18.8-arm64-darwin)
151
151
  racc (~> 1.4)
152
- nokogiri (1.18.7-x86_64-darwin)
152
+ nokogiri (1.18.8-x86_64-darwin)
153
153
  racc (~> 1.4)
154
- nokogiri (1.18.7-x86_64-linux-gnu)
154
+ nokogiri (1.18.8-x86_64-linux-gnu)
155
155
  racc (~> 1.4)
156
- nokogiri (1.18.7-x86_64-linux-musl)
156
+ nokogiri (1.18.8-x86_64-linux-musl)
157
157
  racc (~> 1.4)
158
158
  octokit (4.25.1)
159
159
  faraday (>= 1, < 3)
160
160
  sawyer (~> 0.9)
161
161
  os (1.1.4)
162
- parallel (1.26.3)
162
+ parallel (1.27.0)
163
163
  parser (3.3.8.0)
164
164
  ast (~> 2.4.1)
165
165
  racc
@@ -223,7 +223,7 @@ GEM
223
223
  prism (~> 1.4)
224
224
  rubocop-rake (0.6.0)
225
225
  rubocop (~> 1.0)
226
- rubocop-rspec (3.5.0)
226
+ rubocop-rspec (3.6.0)
227
227
  lint_roller (~> 1.1)
228
228
  rubocop (~> 1.72, >= 1.72.1)
229
229
  ruby-anthropic (0.4.2)
@@ -247,7 +247,7 @@ GEM
247
247
  sqlite3 (2.6.0-x86_64-darwin)
248
248
  sqlite3 (2.6.0-x86_64-linux-gnu)
249
249
  sqlite3 (2.6.0-x86_64-linux-musl)
250
- stringio (3.1.6)
250
+ stringio (3.1.7)
251
251
  strings-ansi (0.2.0)
252
252
  timeout (0.4.3)
253
253
  timers (4.4.0)
@@ -33,6 +33,30 @@ module Boxcars
33
33
  { model_info: model_info }.merge super
34
34
  end
35
35
 
36
+ CTEMPLATE = [
37
+ syst("You are a Ruby on Rails Active Record code generator"),
38
+ syst("Given an input question, first create a syntactically correct Rails Active Record code to run, ",
39
+ "then look at the results of the code and return the answer. Unless the user specifies ",
40
+ "in her question a specific number of examples she wishes to obtain, limit your code ",
41
+ "to at most %<top_k>s results.\n",
42
+ "Never query for all the columns from a specific model, ",
43
+ "only ask for the relevant attributes given the question.\n",
44
+ "Also, pay attention to which attribute is in which model.\n\n",
45
+ "Use the following format:\n",
46
+ "Question: ${{Question here}}\n",
47
+ "ARChanges: ${{Active Record code to compute the number of records going to change}} - ",
48
+ "Only add this line if the ARCode on the next line will make data changes.\n",
49
+ "ARCode: ${{Active Record code to run}} - make sure you use valid code\n",
50
+ "Answer: ${{Final answer here}}\n\n",
51
+ "Only use the following Active Record models: %<model_info>s\n",
52
+ "Pay attention to use only the attribute names that you can see in the model description.\n",
53
+ "Do not make up variable or attribute names, and do not share variables between the code in ARChanges and ARCode\n",
54
+ "Be careful to not query for attributes that do not exist, and to use the format specified above.\n",
55
+ "Finally, try not to use print or puts in your code"
56
+ ),
57
+ user("Question: %<question>s")
58
+ ].freeze
59
+
36
60
  private
37
61
 
38
62
  def get_name
@@ -240,30 +264,6 @@ module Boxcars
240
264
  end
241
265
  end
242
266
 
243
- CTEMPLATE = [
244
- syst("You are a Ruby on Rails Active Record code generator"),
245
- syst("Given an input question, first create a syntactically correct Rails Active Record code to run, ",
246
- "then look at the results of the code and return the answer. Unless the user specifies ",
247
- "in her question a specific number of examples she wishes to obtain, limit your code ",
248
- "to at most %<top_k>s results.\n",
249
- "Never query for all the columns from a specific model, ",
250
- "only ask for the relevant attributes given the question.\n",
251
- "Also, pay attention to which attribute is in which model.\n\n",
252
- "Use the following format:\n",
253
- "Question: ${{Question here}}\n",
254
- "ARChanges: ${{Active Record code to compute the number of records going to change}} - ",
255
- "Only add this line if the ARCode on the next line will make data changes.\n",
256
- "ARCode: ${{Active Record code to run}} - make sure you use valid code\n",
257
- "Answer: ${{Final answer here}}\n\n",
258
- "Only use the following Active Record models: %<model_info>s\n",
259
- "Pay attention to use only the attribute names that you can see in the model description.\n",
260
- "Do not make up variable or attribute names, and do not share variables between the code in ARChanges and ARCode\n",
261
- "Be careful to not query for attributes that do not exist, and to use the format specified above.\n",
262
- "Finally, try not to use print or puts in your code"
263
- ),
264
- user("Question: %<question>s")
265
- ].freeze
266
-
267
267
  # The prompt to use for the engine.
268
268
  def my_prompt
269
269
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -18,27 +18,6 @@ module Boxcars
18
18
  super(engine: engine, prompt: the_prompt, **kwargs)
19
19
  end
20
20
 
21
- private
22
-
23
- def get_embedded_ruby_answer(text)
24
- code = text.split("```ruby\n").last.split("```").first.strip
25
- # code = text[8..-4].split("```").first.strip
26
- ruby_executor = Boxcars::RubyREPL.new
27
- ruby_executor.call(code: code)
28
- end
29
-
30
- def get_answer(text)
31
- case text
32
- when /^```ruby/
33
- get_embedded_ruby_answer(text)
34
- when /^Answer:/
35
- Result.from_text(text)
36
- else
37
- Result.new(status: :error,
38
- explanation: "Error: expecting your response to begin with '```ruby'. Try answering the question again.")
39
- end
40
- end
41
-
42
21
  # our template
43
22
  CTEMPLATE = [
44
23
  syst("You can do basic math, but for any hard calculations that a human could not do ",
@@ -62,6 +41,27 @@ module Boxcars
62
41
  user("%<question>s")
63
42
  ].freeze
64
43
 
44
+ private
45
+
46
+ def get_embedded_ruby_answer(text)
47
+ code = text.split("```ruby\n").last.split("```").first.strip
48
+ # code = text[8..-4].split("```").first.strip
49
+ ruby_executor = Boxcars::RubyREPL.new
50
+ ruby_executor.call(code: code)
51
+ end
52
+
53
+ def get_answer(text)
54
+ case text
55
+ when /^```ruby/
56
+ get_embedded_ruby_answer(text)
57
+ when /^Answer:/
58
+ Result.from_text(text)
59
+ else
60
+ Result.new(status: :error,
61
+ explanation: "Error: expecting your response to begin with '```ruby'. Try answering the question again.")
62
+ end
63
+ end
64
+
65
65
  # The prompt to use for the engine.
66
66
  def my_prompt
67
67
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -41,8 +41,6 @@ module Boxcars
41
41
  answer
42
42
  end
43
43
 
44
- private
45
-
46
44
  ANSWER_LOCATIONS = [
47
45
  %i[answer_box answer],
48
46
  %i[answer_box snippet],
@@ -54,6 +52,8 @@ module Boxcars
54
52
  [:organic_results, 0, :title]
55
53
  ].freeze
56
54
 
55
+ private
56
+
57
57
  def find_answer(res)
58
58
  raise Error, "Got error from SerpAPI: #{res[:error]}" if res[:error]
59
59
 
@@ -32,6 +32,24 @@ module Boxcars
32
32
  { schema: schema, dialect: dialect }.merge super
33
33
  end
34
34
 
35
+ CTEMPLATE = [
36
+ syst("Given an input question, first create a syntactically correct %<dialect>s SQL query to run, ",
37
+ "then look at the results of the query and return the answer. Unless the user specifies ",
38
+ "in her question a specific number of examples he wishes to obtain, always limit your query ",
39
+ "to at most %<top_k>s results using a LIMIT clause. You can order the results by a relevant column ",
40
+ "to return the most interesting examples in the database.\n",
41
+ "Never query for all the columns from a specific table, only ask for the elevant columns given the question.\n",
42
+ "Pay attention to use only the column names that you can see in the schema description. Be careful to ",
43
+ "not query for columns that do not exist. Also, pay attention to which column is in which table.\n",
44
+ "Use the following format:\n",
45
+ "Question: 'Question here'\n",
46
+ "SQLQuery: 'SQL Query to run'\n",
47
+ "SQLResult: 'Result of the SQLQuery'\n",
48
+ "Answer: 'Final answer here'"),
49
+ syst("Only use the following tables:\n%<schema>s"),
50
+ user("Question: %<question>s")
51
+ ].freeze
52
+
35
53
  private
36
54
 
37
55
  def check_tables(rtables, exceptions)
@@ -106,24 +124,6 @@ module Boxcars
106
124
  end
107
125
  end
108
126
 
109
- CTEMPLATE = [
110
- syst("Given an input question, first create a syntactically correct %<dialect>s SQL query to run, ",
111
- "then look at the results of the query and return the answer. Unless the user specifies ",
112
- "in her question a specific number of examples he wishes to obtain, always limit your query ",
113
- "to at most %<top_k>s results using a LIMIT clause. You can order the results by a relevant column ",
114
- "to return the most interesting examples in the database.\n",
115
- "Never query for all the columns from a specific table, only ask for the elevant columns given the question.\n",
116
- "Pay attention to use only the column names that you can see in the schema description. Be careful to ",
117
- "not query for columns that do not exist. Also, pay attention to which column is in which table.\n",
118
- "Use the following format:\n",
119
- "Question: 'Question here'\n",
120
- "SQLQuery: 'SQL Query to run'\n",
121
- "SQLResult: 'Result of the SQLQuery'\n",
122
- "Answer: 'Final answer here'"),
123
- syst("Only use the following tables:\n%<schema>s"),
124
- user("Question: %<question>s")
125
- ].freeze
126
-
127
127
  # The prompt to use for the engine.
128
128
  def my_prompt
129
129
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -29,6 +29,24 @@ module Boxcars
29
29
  { swagger_url: swagger_url, context: context }.merge super
30
30
  end
31
31
 
32
+ # our template
33
+ CTEMPLATE = [
34
+ syst("Study this Open API Swagger file %<swagger_url>s\n",
35
+ "and write a Ruby Program that prints the answer to the following questions using the appropriate API calls:\n",
36
+ "Additional context that you might need in the Ruby program: (%<context>s)\n",
37
+ "Use the following format:\n",
38
+ "${{Question needing API calls and code}}\n",
39
+ "reply only with the following format:\n",
40
+ "```ruby\n${{Ruby code with API calls and code that prints the answer}}\n```\n",
41
+ "```output\n${{Output of your code}}\n```\n\n",
42
+ "Otherwise, if you know the answer and do not need any API calls, you should use this simpler format:\n",
43
+ "${{Question not needing API calls}}\n",
44
+ "Answer: ${{Answer}}\n\n",
45
+ "Do not give an explanation of the answer and make sure your answer starts with either 'Answer:' or '```ruby'. ",
46
+ "Make use of the rest-client gem to make your requests to the API. Just print the answer."),
47
+ user("%<question>s")
48
+ ].freeze
49
+
32
50
  private
33
51
 
34
52
  def get_embedded_ruby_answer(text)
@@ -49,24 +67,6 @@ module Boxcars
49
67
  end
50
68
  end
51
69
 
52
- # our template
53
- CTEMPLATE = [
54
- syst("Study this Open API Swagger file %<swagger_url>s\n",
55
- "and write a Ruby Program that prints the answer to the following questions using the appropriate API calls:\n",
56
- "Additional context that you might need in the Ruby program: (%<context>s)\n",
57
- "Use the following format:\n",
58
- "${{Question needing API calls and code}}\n",
59
- "reply only with the following format:\n",
60
- "```ruby\n${{Ruby code with API calls and code that prints the answer}}\n```\n",
61
- "```output\n${{Output of your code}}\n```\n\n",
62
- "Otherwise, if you know the answer and do not need any API calls, you should use this simpler format:\n",
63
- "${{Question not needing API calls}}\n",
64
- "Answer: ${{Answer}}\n\n",
65
- "Do not give an explanation of the answer and make sure your answer starts with either 'Answer:' or '```ruby'. ",
66
- "Make use of the rest-client gem to make your requests to the API. Just print the answer."),
67
- user("%<question>s")
68
- ].freeze
69
-
70
70
  # The prompt to use for the engine.
71
71
  def my_prompt
72
72
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -30,6 +30,14 @@ module Boxcars
30
30
  { search_content: get_search_content(inputs[:question]) }.merge super
31
31
  end
32
32
 
33
+ # our template
34
+ CTEMPLATE = [
35
+ syst("You are tasked with answering a question using these possibly relevant excerpts from a large volume of text:\n" \
36
+ "```text\n%<search_content>s\n```\n\n",
37
+ "Using the above, just answer the question as if you were answering directly."),
38
+ user("%<question>s")
39
+ ].freeze
40
+
33
41
  private
34
42
 
35
43
  # @param results [Array] The results from the vector search.
@@ -50,14 +58,6 @@ module Boxcars
50
58
  @search_content = get_results_content(results)
51
59
  end
52
60
 
53
- # our template
54
- CTEMPLATE = [
55
- syst("You are tasked with answering a question using these possibly relevant excerpts from a large volume of text:\n" \
56
- "```text\n%<search_content>s\n```\n\n",
57
- "Using the above, just answer the question as if you were answering directly."),
58
- user("%<question>s")
59
- ].freeze
60
-
61
61
  # The prompt to use for the engine.
62
62
  def my_prompt
63
63
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Boxcars
4
+ # A engine that uses Google's API
5
+ class Together < IntelligenceBase
6
+ # The default parameters to use when asking the engine
7
+ DEFAULT_PARAMS = {
8
+ model: "deepseek-ai/DeepSeek-R1-Distill-Llama-70B",
9
+ temperature: 0.1
10
+ }.freeze
11
+
12
+ # the default name of the engine
13
+ DEFAULT_NAME = "DeepSeek R1 Distill Llama 70B AI engine"
14
+ # the default description of the engine
15
+ DEFAULT_DESCRIPTION = "useful for when you need to use DeepSeek AI to process complex content. " \
16
+ "Supports text, images, and other content types"
17
+
18
+ # A DeepSeek Engine is used by Boxcars to generate output from prompts
19
+ # @param name [String] The name of the Engine. Defaults to classname.
20
+ # @param description [String] A description of the Engine.
21
+ # @param prompts [Array<Prompt>] The prompts to use for the Engine.
22
+ # @param batch_size [Integer] The number of prompts to send to the Engine at a time.
23
+ # @param kwargs [Hash] Additional parameters to pass to the Engine.
24
+ def initialize(name: DEFAULT_NAME, description: DEFAULT_DESCRIPTION, prompts: [], batch_size: 20, **kwargs)
25
+ super(provider: :together_ai, description: description, name: name, prompts: prompts, batch_size: batch_size, **kwargs)
26
+ end
27
+
28
+ def default_model_params
29
+ DEFAULT_PARAMS
30
+ end
31
+
32
+ def lookup_provider_api_key(params:)
33
+ Boxcars.configuration.together_api_key(**params)
34
+ end
35
+ end
36
+ end
@@ -89,3 +89,4 @@ require "boxcars/engine/gemini_ai"
89
89
  require "boxcars/engine/intelligence_base"
90
90
  require "boxcars/engine/cerebras"
91
91
  require "boxcars/engine/google"
92
+ require "boxcars/engine/together"
@@ -22,8 +22,6 @@ module Boxcars
22
22
  super(engine: engine, boxcars: boxcars, prompt: prompt, name: name, description: description, **kwargs)
23
23
  end
24
24
 
25
- private
26
-
27
25
  CTEMPLATE = [
28
26
  syst("<training>Answer the following questions as best you can. You have access to the following tools for actions:\n",
29
27
  "%<boxcars_xml>s",
@@ -47,6 +45,8 @@ module Boxcars
47
45
  assi("%<agent_scratchpad>s")
48
46
  ].freeze
49
47
 
48
+ private
49
+
50
50
  # The prompt to use for the train.
51
51
  def my_prompt
52
52
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -33,11 +33,35 @@ module Boxcars
33
33
  [:error, e.message]
34
34
  end
35
35
 
36
- private
37
-
38
36
  # the final answer action string
39
37
  FINAL_ANSWER_ACTION = "Final Answer:"
40
38
 
39
+ CTEMPLATE = [
40
+ syst("Answer the following questions as best you can. You have access to the following actions:\n",
41
+ "%<boxcar_descriptions>s\n",
42
+ "Use the following format:\n",
43
+ "Question: the input question you must answer\n",
44
+ "Thought: you should always think about what to do\n",
45
+ "Action: the action to take, should be one from this list: %<boxcar_names>s\n",
46
+ "Action Input: an input question to the action\n",
47
+ "Observation: the result of the action\n",
48
+ "... (this Thought/Action/Action Input/Observation sequence can repeat N times)\n",
49
+ "Thought: I know the final answer\n",
50
+ "Final Answer: the final answer to the original input question\n",
51
+ "%<next_actions>s\n",
52
+ "Remember to start a line with \"Final Answer:\" to give me the final answer.\n",
53
+ "Also make sure to specify a question for the Action Input.\n",
54
+ "Finally, if you can deduct the answer from the question or observation, you can ",
55
+ "start with \"Final Answer:\" and give me the answer.\n",
56
+ "Begin!"),
57
+ # insert thoughts here from previous runs
58
+ hist,
59
+ user("Question: %<input>s"),
60
+ assi("Thought: %<agent_scratchpad>s")
61
+ ].freeze
62
+
63
+ private
64
+
41
65
  # Parse out the action and input from the engine output.
42
66
  # @param engine_output [String] The output from the engine.
43
67
  # @return [Array<String>] The action and input.
@@ -70,30 +94,6 @@ module Boxcars
70
94
  end
71
95
  end
72
96
 
73
- CTEMPLATE = [
74
- syst("Answer the following questions as best you can. You have access to the following actions:\n",
75
- "%<boxcar_descriptions>s\n",
76
- "Use the following format:\n",
77
- "Question: the input question you must answer\n",
78
- "Thought: you should always think about what to do\n",
79
- "Action: the action to take, should be one from this list: %<boxcar_names>s\n",
80
- "Action Input: an input question to the action\n",
81
- "Observation: the result of the action\n",
82
- "... (this Thought/Action/Action Input/Observation sequence can repeat N times)\n",
83
- "Thought: I know the final answer\n",
84
- "Final Answer: the final answer to the original input question\n",
85
- "%<next_actions>s\n",
86
- "Remember to start a line with \"Final Answer:\" to give me the final answer.\n",
87
- "Also make sure to specify a question for the Action Input.\n",
88
- "Finally, if you can deduct the answer from the question or observation, you can ",
89
- "start with \"Final Answer:\" and give me the answer.\n",
90
- "Begin!"),
91
- # insert thoughts here from previous runs
92
- hist,
93
- user("Question: %<input>s"),
94
- assi("Thought: %<agent_scratchpad>s")
95
- ].freeze
96
-
97
97
  # The prompt to use for the train.
98
98
  def my_prompt
99
99
  @conversation ||= Conversation.new(lines: CTEMPLATE)
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.7.4"
5
+ VERSION = "0.7.5"
6
6
  end
data/lib/boxcars.rb CHANGED
@@ -72,6 +72,11 @@ module Boxcars
72
72
  key_lookup(:gemini_api_key, kwargs)
73
73
  end
74
74
 
75
+ # @return [String] The Together AI API key either from arg or env.
76
+ def together_api_key(**kwargs)
77
+ key_lookup(:together_api_key, kwargs)
78
+ end
79
+
75
80
  private
76
81
 
77
82
  def check_key(key, val)
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.7.4
4
+ version: 0.7.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: 2025-04-16 00:00:00.000000000 Z
12
+ date: 2025-04-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: google_search_results
@@ -176,6 +176,7 @@ files:
176
176
  - lib/boxcars/engine/ollama.rb
177
177
  - lib/boxcars/engine/openai.rb
178
178
  - lib/boxcars/engine/perplexityai.rb
179
+ - lib/boxcars/engine/together.rb
179
180
  - lib/boxcars/generation.rb
180
181
  - lib/boxcars/observation.rb
181
182
  - lib/boxcars/prompt.rb