boxcars 0.10.1 → 0.10.2

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: 35a54151586860bccd1bd38579540f1130802c439cf9a64ea4f66f888dd927a1
4
- data.tar.gz: 8b8b583b53b3d6223450c73376d94b073f393f46ee275532a0bb696c1ff261ea
3
+ metadata.gz: 224720d4944dee8add70e0cbb0db0768c7db74c2541547e600d485f7923cec20
4
+ data.tar.gz: 8f17b105ad4db7a707c08a6ed00923a20003bd30dbe76ad913e689a9de55bc68
5
5
  SHA512:
6
- metadata.gz: 14d6cbf78d9fc5b95d1e956c9f66a5cc1747779f4170043f8469297f3ffc899a7760f39fd0f30377a1524b9a50b852a83bd69728f241b97dd97e6def4ee8c727
7
- data.tar.gz: 19a99e7c1fd1670cec2ea0c0f2091b81943d0606ebff2817f7d24b444f0ed2246039cfef07d1768c95b043ecaf821153aa2bd9e724f07bb4d58e30ff79fc399d
6
+ metadata.gz: 74c8326c4ba3512466437d2c35056f50f28255f7b97ae5b0b2ea21743751eca30b7ee91040fd59f2b2684900864cc079e76f3f1894299635cad441552f6ba8aa
7
+ data.tar.gz: 31700d6ac344c9d66490cd3957bd96cee085605acc8550aa9f03edc7017ee38662392b3cf19d8d547282806bb82c4b5ae569b3da0fccb8c11633b2c84b9b1a91
data/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Recent Updates
6
+
7
+ - Tool-calling runtime naming simplified:
8
+ - `Boxcars::ToolTrain` is now the preferred class name.
9
+ - `Boxcars::MCP.tool_train(...)` is the preferred MCP helper.
10
+ - Compatibility aliases remain available for `ToolCallingTrain` / `tool_calling_train`.
11
+ - Added live multi-provider smoke coverage:
12
+ - `spec/boxcars/llms_live_spec.rb` (opt-in via `RUN_LIVE_LLM_SPECS=true`)
13
+ - `rake spec:llms_live`
14
+ - Provider include/skip controls and per-provider timeout overrides for stable live runs.
15
+ - Provider and extraction reliability updates:
16
+ - Cohere default model updated to `command-a-03-2025`.
17
+ - OpenAI-compatible answer extraction hardened for provider-specific message payload shapes.
18
+ - Live smoke defaults updated for Gemini/Google/Cerebras token budgets.
19
+
5
20
  ### Upgrade Guide (v0.9 -> v1.0 planned)
6
21
 
7
22
  This section tracks the modernization work that is being added in v0.9 with a compatibility window before v1.0 removals.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- boxcars (0.10.1)
4
+ boxcars (0.10.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -19,7 +19,7 @@ Inspired by LangChain, Boxcars brings a Ruby-first design that favors practical
19
19
 
20
20
  - Tool composability by default: package domain logic as `Boxcar` objects and reuse them across assistants, jobs, and services.
21
21
  - Lower cognitive load for Ruby/Rails developers: one consistent programming model (`Boxcar`, `Train`, `Engine`) for controllers, jobs, and service objects instead of one-off wrappers per provider.
22
- - Multiple orchestration modes: keep legacy text ReAct (`Boxcars::ZeroShot`) or use native provider tool calling (`Boxcars::ToolCallingTrain`).
22
+ - Multiple orchestration modes: keep legacy text ReAct (`Boxcars::ZeroShot`) or use native provider tool calling (`Boxcars::ToolTrain`).
23
23
  - Structured output paths: enforce JSON contracts with JSON Schema through `JSONEngineBoxcar`.
24
24
  - MCP-ready integration: connect MCP servers over stdio and merge MCP tools with local Boxcars in one tool-calling runtime.
25
25
  - Provider flexibility without a rewrite: use OpenAI, Anthropic, Groq, Gemini, Ollama, Perplexity, and more through shared engine patterns.
@@ -39,6 +39,7 @@ Notebook migration expectations for the OpenAI client migration are documented i
39
39
  ### Current Upgrade Notes (toward v1.0)
40
40
 
41
41
  - `Boxcars::Openai` now defaults to `gpt-5-mini` and uses the official OpenAI client path.
42
+ - `Boxcars::Cohere` now defaults to `command-a-03-2025` (legacy `command-r*` model IDs were retired by Cohere).
42
43
  - Runtime ActiveSupport/ActiveRecord targets are now `~> 8.1`.
43
44
  - Swagger workflows now use Faraday guidance. `rest-client` is no longer a Boxcars runtime dependency.
44
45
  - `intelligence` and `gpt4all` are now optional dependencies:
@@ -59,7 +60,7 @@ gem "gpt4all"
59
60
  All of these concepts are in a module named Boxcars:
60
61
 
61
62
  - Boxcar - an encapsulation that performs something of interest (such as search, math, SQL, an Active Record Query, or an API call to a service). A Boxcar can use an Engine (described below) to do its work, and if not specified but needed, the default Engine is used `Boxcars.engine`.
62
- - Train - Given a list of Boxcars and 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. `Boxcars::ZeroShot` is the legacy text ReAct implementation, and `Boxcars::ToolCallingTrain` is the newer native tool-calling runtime.
63
+ - Train - Given a list of Boxcars and 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. `Boxcars::ZeroShot` is the legacy text ReAct implementation, and `Boxcars::ToolTrain` is the newer native tool-calling runtime.
63
64
  - Prompt - used by an Engine to generate text results. Our Boxcars have built-in prompts, but you have the flexibility to change or augment them if you so desire.
64
65
  - Engine - an entity that generates text from a Prompt. OpenAI's LLM text generator is the default Engine if no other is specified, and you can override the default engine if so desired (`Boxcars.configuration.default_engine`). We have an Engine for Anthropic's Claude API named `Boxcars::Anthropic`, and another Engine for local GPT named `Boxcars::Gpt4allEng` (requires the optional `gpt4all` gem).
65
66
  - VectorStore - a place to store and query vectors.
@@ -246,7 +247,7 @@ engine = Boxcars::Engines.engine(model: "gpt-4o")
246
247
  mcp_client = Boxcars::MCP.stdio(command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"])
247
248
 
248
249
  begin
249
- train = Boxcars::MCP.tool_calling_train(
250
+ train = Boxcars::MCP.tool_train(
250
251
  engine: engine,
251
252
  boxcars: [Boxcars::Calculator.new],
252
253
  clients: [mcp_client],
@@ -259,7 +260,7 @@ ensure
259
260
  end
260
261
  ```
261
262
 
262
- `Boxcars::MCP.tool_calling_train(...)` combines local Boxcars and MCP-discovered tools into a `Boxcars::ToolCallingTrain`.
263
+ `Boxcars::MCP.tool_train(...)` combines local Boxcars and MCP-discovered tools into a `Boxcars::ToolTrain`.
263
264
 
264
265
  ### More Examples
265
266
  See [this](https://github.com/BoxcarsAI/boxcars/blob/main/notebooks/boxcars_examples.ipynb) Jupyter Notebook for more examples.
@@ -512,7 +513,7 @@ end
512
513
  Override the model for specific engine instances:
513
514
 
514
515
  ```ruby
515
- # Global default is gemini-flash, but use different models per boxcar
516
+ # Global default is gemini-2.5-flash, but use different models per boxcar
516
517
  default_engine = Boxcars::Engines.engine # Uses global default
517
518
  gpt_engine = Boxcars::Engines.engine(model: "gpt-4o") # Uses GPT-4o
518
519
  claude_engine = Boxcars::Engines.engine(model: "sonnet") # Uses Claude Sonnet
data/Rakefile CHANGED
@@ -21,7 +21,7 @@ namespace :spec do
21
21
  spec/boxcars/engines_spec.rb
22
22
  spec/boxcars/engine/capabilities_spec.rb
23
23
  spec/boxcars/boxcar_tool_spec.rb
24
- spec/boxcars/tool_calling_train_spec.rb
24
+ spec/boxcars/tool_train_spec.rb
25
25
  spec/boxcars/json_engine_boxcar_schema_spec.rb
26
26
  spec/boxcars/mcp_helpers_spec.rb
27
27
  spec/boxcars/mcp_stdio_client_spec.rb
@@ -51,6 +51,11 @@ namespace :spec do
51
51
  sh "bundle exec rspec #{NOTEBOOK_SMOKE_SPECS.join(' ')}"
52
52
  end
53
53
 
54
+ desc "Run live smoke checks for all configured LLM providers (.env supported)"
55
+ task :llms_live do
56
+ sh "RUN_LIVE_LLM_SPECS=true NO_VCR=true bundle exec rspec spec/boxcars/llms_live_spec.rb"
57
+ end
58
+
54
59
  desc "Run live notebook compatibility checks (requires OPENAI_ACCESS_TOKEN)"
55
60
  task :notebooks_live do
56
61
  sh "bundle exec ruby script/notebooks_live_check.rb"
data/UPGRADING.md CHANGED
@@ -6,7 +6,7 @@ This guide covers the migration path for the modernization work added in v0.9 an
6
6
 
7
7
  v0.9 introduces:
8
8
 
9
- - Native tool-calling runtime via `Boxcars::ToolCallingTrain`
9
+ - Native tool-calling runtime via `Boxcars::ToolTrain`
10
10
  - MCP as a first-class integration path
11
11
  - JSON Schema support for `JSONEngineBoxcar`
12
12
  - Deprecated model alias warnings with optional strict mode
@@ -16,6 +16,11 @@ v1.0 is expected to:
16
16
  - Remove deprecated model aliases
17
17
  - Prefer explicit model names (with a small curated alias set)
18
18
 
19
+ ## Provider Model Refresh Notes (v0.10.x)
20
+
21
+ - Cohere retired legacy `command-r*` model IDs. Boxcars now defaults Cohere to `command-a-03-2025`.
22
+ - If you pinned older Cohere IDs (`command-r`, `command-r-plus`, etc.), update to an available model in your Cohere account.
23
+
19
24
  ## Constructor Cleanup: `prompts:` Removed From Engine Initializers
20
25
 
21
26
  Engine constructors no longer accept a `prompts:` keyword argument.
@@ -151,7 +156,7 @@ Boxcars::Engines.strict_deprecated_aliases = true
151
156
 
152
157
  ## 3. Migrate ReAct/Text Trains to Native Tool Calling (Optional, Recommended)
153
158
 
154
- Existing `ZeroShot` / XML trains continue to work. `ToolCallingTrain` is the opt-in modern runtime.
159
+ Existing `ZeroShot` / XML trains continue to work. `ToolTrain` is the opt-in modern runtime.
155
160
 
156
161
  ### Before (legacy text ReAct)
157
162
 
@@ -165,7 +170,7 @@ puts train.run("What is 12 * 9 and what is the weather in Austin?")
165
170
 
166
171
  ```ruby
167
172
  boxcars = [Boxcars::Calculator.new, Boxcars::GoogleSearch.new]
168
- train = Boxcars::ToolCallingTrain.new(
173
+ train = Boxcars::ToolTrain.new(
169
174
  boxcars: boxcars,
170
175
  engine: Boxcars::Engines.engine(model: "gpt-4o")
171
176
  )
@@ -174,7 +179,7 @@ puts train.run("What is 12 * 9 and what is the weather in Austin?")
174
179
 
175
180
  ### Notes
176
181
 
177
- - `ToolCallingTrain` requires an engine that supports native tool-calling.
182
+ - `ToolTrain` requires an engine that supports native tool-calling.
178
183
  - OpenAI chat models and OpenAI Responses API (`gpt-5` style) are supported by the current runtime path.
179
184
 
180
185
  ## 4. Add MCP Tools (Optional, Recommended)
@@ -189,7 +194,7 @@ mcp = Boxcars::MCP.stdio(
189
194
  )
190
195
 
191
196
  begin
192
- train = Boxcars::MCP.tool_calling_train(
197
+ train = Boxcars::MCP.tool_train(
193
198
  engine: engine,
194
199
  boxcars: [Boxcars::Calculator.new],
195
200
  clients: [mcp],
@@ -236,7 +241,7 @@ boxcar = Boxcars::JSONEngineBoxcar.new(json_schema: schema, json_schema_strict:
236
241
 
237
242
  1. Replace deprecated aliases in application code.
238
243
  2. Enable strict alias mode in CI.
239
- 3. Migrate one workflow from `ZeroShot` to `ToolCallingTrain`.
244
+ 3. Migrate one workflow from `ZeroShot` to `ToolTrain`.
240
245
  4. Add MCP tools where they simplify app-specific integrations.
241
246
  5. Add JSON Schema to `JSONEngineBoxcar` uses that need reliable structure.
242
247
  6. Upgrade to v1.0 after strict mode stays green.
@@ -266,7 +271,7 @@ This shared factory seam is used by all OpenAI-compatible engines, so client wir
266
271
 
267
272
  - Prefer `Boxcars::Engines.engine(...)` or engine classes directly (`Boxcars::Openai`, `Boxcars::Groq`, etc.).
268
273
  - Avoid depending on the exact underlying client object class returned inside engine internals.
269
- - Prefer explicit model names and `ToolCallingTrain` for new builds.
274
+ - Prefer explicit model names and `ToolTrain` for new builds.
270
275
 
271
276
  ### OpenAI client defaults (v0.10+)
272
277
 
@@ -362,7 +367,7 @@ OPENAI_ACCESS_TOKEN=... bundle exec rake spec:vcr_openai_refresh
362
367
 
363
368
  - `Boxcars::Openai` public constructor and `#run` behavior
364
369
  - `Boxcars::Engines.engine(model: ...)`
365
- - `ToolCallingTrain` usage
370
+ - `ToolTrain` usage
366
371
  - `JSONEngineBoxcar` usage (including `json_schema:` support)
367
372
  - MCP + Boxcar composition APIs
368
373
 
@@ -11,7 +11,7 @@ module Boxcars
11
11
 
12
12
  # The default parameters to use when asking the engine.
13
13
  DEFAULT_PARAMS = {
14
- model: "command-r-plus",
14
+ model: "command-a-03-2025",
15
15
  max_tokens: 4000,
16
16
  max_input_tokens: 1000,
17
17
  temperature: 0.2
@@ -101,6 +101,7 @@ module Boxcars
101
101
 
102
102
  if raw_response.status == 200
103
103
  parsed_json = normalize_generate_response(JSON.parse(raw_response.body))
104
+ parsed_json["text"] ||= extract_cohere_text(parsed_json)
104
105
 
105
106
  if parsed_json["error"]
106
107
  response_data[:success] = false
@@ -112,9 +113,13 @@ module Boxcars
112
113
  []
113
114
  end
114
115
  input_tokens = parsed_json.dig("meta", "tokens", "input_tokens") ||
115
- parsed_json.dig("meta", "billed_units", "input_tokens")
116
+ parsed_json.dig("meta", "billed_units", "input_tokens") ||
117
+ parsed_json.dig("usage", "tokens", "input_tokens") ||
118
+ parsed_json.dig("usage", "billed_units", "input_tokens")
116
119
  output_tokens = parsed_json.dig("meta", "tokens", "output_tokens") ||
117
- parsed_json.dig("meta", "billed_units", "output_tokens")
120
+ parsed_json.dig("meta", "billed_units", "output_tokens") ||
121
+ parsed_json.dig("usage", "tokens", "output_tokens") ||
122
+ parsed_json.dig("usage", "billed_units", "output_tokens")
118
123
  if input_tokens || output_tokens
119
124
  parsed_json["usage"] ||= {
120
125
  "prompt_tokens" => input_tokens.to_i,
@@ -193,23 +198,78 @@ module Boxcars
193
198
  end
194
199
 
195
200
  def post_cohere_chat(params, api_key)
196
- cohere_connection(api_key).post { |req| req.body = params.to_json }
201
+ v2_response = cohere_connection(api_key, version: :v2).post do |req|
202
+ req.body = cohere_v2_payload(params).to_json
203
+ end
204
+
205
+ return v2_response unless v2_response.status.to_i == 404
206
+
207
+ cohere_connection(api_key, version: :v1).post do |req|
208
+ req.body = cohere_v1_payload(params).to_json
209
+ end
197
210
  end
198
211
 
199
- def cohere_connection(api_key)
200
- Faraday.new('https://api.cohere.ai/v1/chat') do |faraday|
212
+ def cohere_connection(api_key, version:)
213
+ endpoint = version == :v2 ? 'https://api.cohere.com/v2/chat' : 'https://api.cohere.ai/v1/chat'
214
+ Faraday.new(endpoint) do |faraday|
201
215
  faraday.request :url_encoded
202
216
  faraday.headers['Authorization'] = "Bearer #{api_key}"
203
217
  faraday.headers['Content-Type'] = 'application/json'
204
218
  end
205
219
  end
206
220
 
221
+ def cohere_v2_payload(params)
222
+ payload = {
223
+ model: params[:model],
224
+ messages: [{ role: "user", content: params[:message].to_s }]
225
+ }
226
+
227
+ payload[:max_tokens] = params[:max_tokens] if params.key?(:max_tokens)
228
+ payload[:temperature] = params[:temperature] if params.key?(:temperature)
229
+ payload[:p] = params[:p] if params.key?(:p)
230
+ payload[:k] = params[:k] if params.key?(:k)
231
+ payload[:stop_sequences] = params[:stop_sequences] if params.key?(:stop_sequences)
232
+ payload
233
+ end
234
+
235
+ def cohere_v1_payload(params)
236
+ params
237
+ end
238
+
207
239
  def ensure_cohere_api_key!(api_key, error_class:, message:)
208
240
  return unless api_key.to_s.strip.empty?
209
241
 
210
242
  raise error_class, message
211
243
  end
212
244
 
245
+ def extract_cohere_text(parsed_json)
246
+ text = parsed_json["text"]
247
+ return text if text.is_a?(String) && !text.strip.empty?
248
+
249
+ message_content = parsed_json.dig("message", "content")
250
+ case message_content
251
+ when String
252
+ stripped = message_content.strip
253
+ return stripped unless stripped.empty?
254
+ when Array
255
+ texts = message_content.filter_map do |part|
256
+ next unless part.is_a?(Hash)
257
+
258
+ if part["text"].is_a?(String)
259
+ part["text"]
260
+ elsif part["text"].is_a?(Hash)
261
+ part["text"]["value"] || part["text"]["text"]
262
+ elsif part["content"].is_a?(String)
263
+ part["content"]
264
+ end
265
+ end
266
+ joined = texts.join("\n").strip
267
+ return joined unless joined.empty?
268
+ end
269
+
270
+ nil
271
+ end
272
+
213
273
  def parse_cohere_response_body(body)
214
274
  JSON.parse(body, symbolize_names: true)
215
275
  end
@@ -276,7 +276,9 @@ module Boxcars
276
276
  def extract_answer_from_choices(choices)
277
277
  raise Error, "OpenAI: No choices found in response" unless choices.is_a?(Array) && choices.any?
278
278
 
279
- content = choices.map { |c| c.dig("message", "content") }.compact
279
+ content = choices.filter_map do |choice|
280
+ extract_choice_message_text(choice)
281
+ end
280
282
  return content.join("\n").strip unless content.empty?
281
283
 
282
284
  text = choices.map { |c| c["text"] }.compact
@@ -285,6 +287,65 @@ module Boxcars
285
287
  raise Error, "OpenAI: Could not extract answer from choices"
286
288
  end
287
289
 
290
+ def extract_choice_message_text(choice)
291
+ return nil unless choice.is_a?(Hash)
292
+
293
+ message = choice["message"]
294
+ return nil unless message.is_a?(Hash)
295
+
296
+ content = message["content"]
297
+ extract_text_from_message_content(content)
298
+ end
299
+
300
+ def extract_text_from_message_content(content)
301
+ case content
302
+ when String
303
+ stripped = content.strip
304
+ return stripped unless stripped.empty?
305
+ when Array
306
+ texts = content.filter_map do |part|
307
+ extract_text_from_message_part(part)
308
+ end
309
+ joined = texts.join("\n").strip
310
+ return joined unless joined.empty?
311
+ when Hash
312
+ text = content["text"] || content["content"] || content["value"]
313
+ if text.is_a?(String)
314
+ stripped = text.strip
315
+ return stripped unless stripped.empty?
316
+ end
317
+ end
318
+
319
+ nil
320
+ end
321
+
322
+ def extract_text_from_message_part(part)
323
+ return nil unless part.is_a?(Hash)
324
+
325
+ text = part["text"]
326
+ if text.is_a?(String)
327
+ stripped = text.strip
328
+ return stripped unless stripped.empty?
329
+ elsif text.is_a?(Hash)
330
+ value = text["value"] || text["text"]
331
+ if value.is_a?(String)
332
+ stripped = value.strip
333
+ return stripped unless stripped.empty?
334
+ end
335
+ end
336
+
337
+ # Some providers place text directly on the part.
338
+ %w[content value].each do |field|
339
+ value = part[field]
340
+ next unless value.is_a?(String)
341
+
342
+ stripped = value.strip
343
+ return stripped unless stripped.empty?
344
+ end
345
+
346
+ nil
347
+ end
348
+
288
349
  def extract_answer_from_output(output_items) # rubocop:disable Metrics/PerceivedComplexity,Metrics/MethodLength
289
350
  return nil unless output_items.is_a?(Array) && output_items.any?
290
351
 
data/lib/boxcars/mcp.rb CHANGED
@@ -11,7 +11,7 @@ module Boxcars
11
11
  StdioClient.new(command:, args:, **kwargs).connect!
12
12
  end
13
13
 
14
- # Build a ToolCallingTrain from local Boxcars plus tools discovered from
14
+ # Build a ToolTrain from local Boxcars plus tools discovered from
15
15
  # one or more MCP clients.
16
16
  #
17
17
  # @param engine [Boxcars::Engine] Tool-calling capable engine (required)
@@ -19,10 +19,10 @@ module Boxcars
19
19
  # @param clients [Array<Boxcars::MCP::Client>] MCP clients to discover tools from
20
20
  # @param client_name_prefixes [Hash,Integer=>String] Optional prefixes by client index or object_id
21
21
  # @param mcp_return_direct [Boolean] Whether discovered MCP boxcars return direct
22
- # @param train_kwargs [Hash] Additional args for Boxcars::ToolCallingTrain
23
- def self.tool_calling_train(engine:, boxcars: [], clients: [], client_name_prefixes: {}, mcp_return_direct: false, **train_kwargs)
24
- unless defined?(Boxcars::ToolCallingTrain)
25
- raise Boxcars::Error, "Boxcars::ToolCallingTrain is not loaded. Require 'boxcars' before using MCP helpers."
22
+ # @param train_kwargs [Hash] Additional args for Boxcars::ToolTrain
23
+ def self.tool_train(engine:, boxcars: [], clients: [], client_name_prefixes: {}, mcp_return_direct: false, **train_kwargs)
24
+ unless defined?(Boxcars::ToolTrain)
25
+ raise Boxcars::Error, "Boxcars::ToolTrain is not loaded. Require 'boxcars' before using MCP helpers."
26
26
  end
27
27
 
28
28
  combined_boxcars = Array(boxcars).dup
@@ -33,7 +33,12 @@ module Boxcars
33
33
  )
34
34
  end
35
35
 
36
- Boxcars::ToolCallingTrain.new(boxcars: combined_boxcars, engine:, **train_kwargs)
36
+ Boxcars::ToolTrain.new(boxcars: combined_boxcars, engine:, **train_kwargs)
37
+ end
38
+
39
+ # Backwards-compatible helper alias for initial v0.10 naming.
40
+ def self.tool_calling_train(...)
41
+ tool_train(...)
37
42
  end
38
43
 
39
44
  def self.mcp_client_prefix(client, index, client_name_prefixes)
@@ -4,7 +4,7 @@ require "json"
4
4
 
5
5
  module Boxcars
6
6
  # A Train runtime that uses native LLM tool-calling instead of text ReAct parsing.
7
- class ToolCallingTrain < Train
7
+ class ToolTrain < Train
8
8
  attr_accessor :wants_next_actions
9
9
 
10
10
  # Lightweight prompt wrapper so engine adapters can send an exact message list.
@@ -381,4 +381,7 @@ module Boxcars
381
381
  )
382
382
  end
383
383
  end
384
+
385
+ # Backwards-compatible alias for the initial v0.10 naming.
386
+ ToolCallingTrain = ToolTrain
384
387
  end
data/lib/boxcars/train.rb CHANGED
@@ -254,4 +254,4 @@ require "boxcars/train/train_finish"
254
254
  require "boxcars/train/zero_shot"
255
255
  require "boxcars/train/xml_train"
256
256
  require "boxcars/train/xml_zero_shot"
257
- require "boxcars/train/tool_calling_train"
257
+ require "boxcars/train/tool_train"
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Boxcars
4
4
  # The current version of the gem.
5
- VERSION = "0.10.1"
5
+ VERSION = "0.10.2"
6
6
  end
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.10.1
4
+ version: 0.10.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francis Sullivan
@@ -89,7 +89,7 @@ files:
89
89
  - lib/boxcars/result.rb
90
90
  - lib/boxcars/ruby_repl.rb
91
91
  - lib/boxcars/train.rb
92
- - lib/boxcars/train/tool_calling_train.rb
92
+ - lib/boxcars/train/tool_train.rb
93
93
  - lib/boxcars/train/train_action.rb
94
94
  - lib/boxcars/train/train_finish.rb
95
95
  - lib/boxcars/train/xml_train.rb