boxcars 0.10.9 → 0.10.11
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/Gemfile.lock +39 -38
- data/docs/boxcars_guide.md +21 -0
- data/lib/boxcars/engine/anthropic.rb +56 -9
- data/lib/boxcars/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 759acf707674768e5d7ced63f2cfea2543077c0680b5d2e6de7f157c43a5e63e
|
|
4
|
+
data.tar.gz: eb7b9ee285c072634a8ce1bd1a8be4d8ca1e14e14adcac7a4f181add50878163
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 93efe7f98f822323a740d4bc4f98b5a92098a7cb1a14022e5a63166fab5f28d8e6f6ca7597ab229d72be6c35a9c11460152d24c6aeaf2b5e52777d6328f8436e
|
|
7
|
+
data.tar.gz: 423b48707ab590debe87ac73872613084bc7c6a1cf9b4258fc48379320585a7efc7cc8717e8ea32097ef13dd76cd95f924c44105623f5b3a2187cccd46caf0a2
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.10.11] - 2026-06-26
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Anthropic Opus 4.7 requests now omit unsupported sampling parameters (`temperature`, `top_p`, and `top_k`) while preserving existing defaults for older Claude models.
|
|
10
|
+
|
|
11
|
+
### Maintenance
|
|
12
|
+
|
|
13
|
+
- Refreshed bundled dependencies and applied RuboCop autocorrections for the release.
|
|
14
|
+
|
|
15
|
+
## [0.10.10] - 2026-05-07
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Anthropic responses now extract and join all text-bearing content blocks, including Claude responses where `thinking` blocks precede the final text block.
|
|
20
|
+
|
|
5
21
|
## [0.10.9] - 2026-04-30
|
|
6
22
|
|
|
7
23
|
### Fixed
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
boxcars (0.10.
|
|
4
|
+
boxcars (0.10.11)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
@@ -30,13 +30,12 @@ GEM
|
|
|
30
30
|
ast (2.4.3)
|
|
31
31
|
base64 (0.3.0)
|
|
32
32
|
bigdecimal (4.1.2)
|
|
33
|
-
cgi (0.5.
|
|
34
|
-
concurrent-ruby (1.3.
|
|
33
|
+
cgi (0.5.2)
|
|
34
|
+
concurrent-ruby (1.3.7)
|
|
35
35
|
connection_pool (3.0.2)
|
|
36
36
|
crack (1.0.1)
|
|
37
37
|
bigdecimal
|
|
38
38
|
rexml
|
|
39
|
-
date (3.5.1)
|
|
40
39
|
debug (1.11.1)
|
|
41
40
|
irb (~> 1.10)
|
|
42
41
|
reline (>= 0.3.8)
|
|
@@ -45,18 +44,18 @@ GEM
|
|
|
45
44
|
drb (2.2.3)
|
|
46
45
|
erb (6.0.4)
|
|
47
46
|
event_stream_parser (1.0.0)
|
|
48
|
-
faraday (2.14.
|
|
47
|
+
faraday (2.14.3)
|
|
49
48
|
faraday-net_http (>= 2.0, < 3.5)
|
|
50
49
|
json
|
|
51
50
|
logger
|
|
52
51
|
faraday-multipart (1.2.0)
|
|
53
52
|
multipart-post (~> 2.0)
|
|
54
|
-
faraday-net_http (3.4.
|
|
53
|
+
faraday-net_http (3.4.4)
|
|
55
54
|
net-http (~> 0.5)
|
|
56
55
|
google_search_results (2.2.0)
|
|
57
56
|
hashdiff (1.2.1)
|
|
58
57
|
hnswlib (0.9.3)
|
|
59
|
-
i18n (1.
|
|
58
|
+
i18n (1.15.2)
|
|
60
59
|
concurrent-ruby (~> 1.0)
|
|
61
60
|
io-console (0.8.2)
|
|
62
61
|
irb (1.18.0)
|
|
@@ -64,33 +63,33 @@ GEM
|
|
|
64
63
|
prism (>= 1.3.0)
|
|
65
64
|
rdoc (>= 4.0.0)
|
|
66
65
|
reline (>= 0.4.2)
|
|
67
|
-
json (2.
|
|
66
|
+
json (2.20.0)
|
|
68
67
|
language_server-protocol (3.17.0.5)
|
|
69
68
|
lint_roller (1.1.0)
|
|
70
69
|
logger (1.7.0)
|
|
71
|
-
minitest (6.0.
|
|
70
|
+
minitest (6.0.6)
|
|
72
71
|
drb (~> 2.0)
|
|
73
72
|
prism (~> 1.5)
|
|
74
73
|
multipart-post (2.4.1)
|
|
75
74
|
net-http (0.9.1)
|
|
76
75
|
uri (>= 0.11.1)
|
|
77
|
-
nokogiri (1.19.
|
|
76
|
+
nokogiri (1.19.4-aarch64-linux-gnu)
|
|
78
77
|
racc (~> 1.4)
|
|
79
|
-
nokogiri (1.19.
|
|
78
|
+
nokogiri (1.19.4-aarch64-linux-musl)
|
|
80
79
|
racc (~> 1.4)
|
|
81
|
-
nokogiri (1.19.
|
|
80
|
+
nokogiri (1.19.4-arm-linux-gnu)
|
|
82
81
|
racc (~> 1.4)
|
|
83
|
-
nokogiri (1.19.
|
|
82
|
+
nokogiri (1.19.4-arm-linux-musl)
|
|
84
83
|
racc (~> 1.4)
|
|
85
|
-
nokogiri (1.19.
|
|
84
|
+
nokogiri (1.19.4-arm64-darwin)
|
|
86
85
|
racc (~> 1.4)
|
|
87
|
-
nokogiri (1.19.
|
|
86
|
+
nokogiri (1.19.4-x86_64-darwin)
|
|
88
87
|
racc (~> 1.4)
|
|
89
|
-
nokogiri (1.19.
|
|
88
|
+
nokogiri (1.19.4-x86_64-linux-gnu)
|
|
90
89
|
racc (~> 1.4)
|
|
91
|
-
nokogiri (1.19.
|
|
90
|
+
nokogiri (1.19.4-x86_64-linux-musl)
|
|
92
91
|
racc (~> 1.4)
|
|
93
|
-
openai (0.
|
|
92
|
+
openai (0.68.0)
|
|
94
93
|
base64
|
|
95
94
|
cgi
|
|
96
95
|
connection_pool
|
|
@@ -106,22 +105,24 @@ GEM
|
|
|
106
105
|
pg (1.6.3-x86_64-linux)
|
|
107
106
|
pg (1.6.3-x86_64-linux-musl)
|
|
108
107
|
pgvector (0.3.3)
|
|
109
|
-
posthog-ruby (3.
|
|
108
|
+
posthog-ruby (3.14.3)
|
|
110
109
|
concurrent-ruby (~> 1)
|
|
111
|
-
pp (0.6.
|
|
110
|
+
pp (0.6.4)
|
|
112
111
|
prettyprint
|
|
113
112
|
prettyprint (0.2.0)
|
|
114
113
|
prism (1.9.0)
|
|
115
|
-
psych (5.3.1)
|
|
116
|
-
date
|
|
117
|
-
stringio
|
|
118
114
|
public_suffix (7.0.5)
|
|
119
115
|
racc (1.8.1)
|
|
120
116
|
rainbow (3.1.1)
|
|
121
117
|
rake (13.4.2)
|
|
122
|
-
|
|
118
|
+
rbs (4.0.3)
|
|
119
|
+
logger
|
|
120
|
+
prism (>= 1.6.0)
|
|
121
|
+
tsort
|
|
122
|
+
rdoc (8.0.0)
|
|
123
123
|
erb
|
|
124
|
-
|
|
124
|
+
prism (>= 1.6.0)
|
|
125
|
+
rbs (>= 4.0.0)
|
|
125
126
|
tsort
|
|
126
127
|
regexp_parser (2.12.0)
|
|
127
128
|
reline (0.6.3)
|
|
@@ -140,7 +141,7 @@ GEM
|
|
|
140
141
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
141
142
|
rspec-support (~> 3.13.0)
|
|
142
143
|
rspec-support (3.13.7)
|
|
143
|
-
rubocop (1.
|
|
144
|
+
rubocop (1.88.0)
|
|
144
145
|
json (~> 2.3)
|
|
145
146
|
language_server-protocol (~> 3.17.0.2)
|
|
146
147
|
lint_roller (~> 1.1.0)
|
|
@@ -157,26 +158,26 @@ GEM
|
|
|
157
158
|
rubocop-rake (0.7.1)
|
|
158
159
|
lint_roller (~> 1.1)
|
|
159
160
|
rubocop (>= 1.72.1)
|
|
160
|
-
rubocop-rspec (3.
|
|
161
|
+
rubocop-rspec (3.10.2)
|
|
161
162
|
lint_roller (~> 1.1)
|
|
162
|
-
|
|
163
|
+
regexp_parser (>= 2.0)
|
|
164
|
+
rubocop (~> 1.86, >= 1.86.2)
|
|
163
165
|
ruby-anthropic (0.4.2)
|
|
164
166
|
event_stream_parser (>= 0.3.0, < 2.0.0)
|
|
165
167
|
faraday (>= 1)
|
|
166
168
|
faraday-multipart (>= 1)
|
|
167
169
|
ruby-progressbar (1.13.0)
|
|
168
170
|
securerandom (0.4.1)
|
|
169
|
-
sequel (5.
|
|
171
|
+
sequel (5.105.0)
|
|
170
172
|
bigdecimal
|
|
171
|
-
sqlite3 (2.9.
|
|
172
|
-
sqlite3 (2.9.
|
|
173
|
-
sqlite3 (2.9.
|
|
174
|
-
sqlite3 (2.9.
|
|
175
|
-
sqlite3 (2.9.
|
|
176
|
-
sqlite3 (2.9.
|
|
177
|
-
sqlite3 (2.9.
|
|
178
|
-
sqlite3 (2.9.
|
|
179
|
-
stringio (3.2.0)
|
|
173
|
+
sqlite3 (2.9.5-aarch64-linux-gnu)
|
|
174
|
+
sqlite3 (2.9.5-aarch64-linux-musl)
|
|
175
|
+
sqlite3 (2.9.5-arm-linux-gnu)
|
|
176
|
+
sqlite3 (2.9.5-arm-linux-musl)
|
|
177
|
+
sqlite3 (2.9.5-arm64-darwin)
|
|
178
|
+
sqlite3 (2.9.5-x86_64-darwin)
|
|
179
|
+
sqlite3 (2.9.5-x86_64-linux-gnu)
|
|
180
|
+
sqlite3 (2.9.5-x86_64-linux-musl)
|
|
180
181
|
timeout (0.6.1)
|
|
181
182
|
tsort (0.2.0)
|
|
182
183
|
tzinfo (2.0.6)
|
data/docs/boxcars_guide.md
CHANGED
|
@@ -179,6 +179,27 @@ engine.run("Write a one-line summary")
|
|
|
179
179
|
|
|
180
180
|
Groq, Gemini, Ollama, Google, Cerebras, and Together all use the same official OpenAI client path with provider-specific base URLs.
|
|
181
181
|
|
|
182
|
+
For enterprise deployments, the same OpenAI-compatible path can point at an
|
|
183
|
+
internal model gateway or AI control plane. For example, Tuning Engines users can
|
|
184
|
+
set an inference key and base URL while keeping regular OpenAI behavior as the
|
|
185
|
+
default fallback:
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
Boxcars.configure do |config|
|
|
189
|
+
config.openai_official_client_builder = lambda do |access_token:, uri_base:, organization_id:, log_errors:|
|
|
190
|
+
OpenAI::Client.new(
|
|
191
|
+
api_key: ENV.fetch("TUNING_ENGINES_INFERENCE_KEY", access_token),
|
|
192
|
+
base_url: ENV.fetch("OPENAI_BASE_URL", uri_base),
|
|
193
|
+
organization: organization_id
|
|
194
|
+
)
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
This is useful when model calls need centralized routing, audit trails,
|
|
200
|
+
guardrails, approval workflows, or cost controls before reaching the final model
|
|
201
|
+
provider.
|
|
202
|
+
|
|
182
203
|
#### Custom Client Builder
|
|
183
204
|
|
|
184
205
|
If you want explicit control over the official SDK client shape:
|
|
@@ -15,6 +15,8 @@ module Boxcars
|
|
|
15
15
|
max_tokens: 4096,
|
|
16
16
|
temperature: 0.1
|
|
17
17
|
}.freeze
|
|
18
|
+
OPUS_4_7_MODEL_PREFIX = "claude-opus-4-7"
|
|
19
|
+
OPUS_4_7_UNSUPPORTED_SAMPLING_PARAMS = %i[temperature top_p top_k].freeze
|
|
18
20
|
|
|
19
21
|
# The default name of the engine.
|
|
20
22
|
DEFAULT_NAME = "Anthropic engine"
|
|
@@ -27,7 +29,7 @@ module Boxcars
|
|
|
27
29
|
raise ArgumentError, "unknown keyword: :prompts" if kwargs.key?(:prompts)
|
|
28
30
|
|
|
29
31
|
user_id = kwargs.delete(:user_id)
|
|
30
|
-
@llm_params = DEFAULT_PARAMS.merge(kwargs)
|
|
32
|
+
@llm_params = remove_opus_4_7_unsupported_sampling_params(DEFAULT_PARAMS.merge(kwargs))
|
|
31
33
|
super(description:, name:, batch_size: 20, user_id:)
|
|
32
34
|
end
|
|
33
35
|
|
|
@@ -83,6 +85,7 @@ module Boxcars
|
|
|
83
85
|
params[:stop_sequences] = params.delete(:stop) if params.key?(:stop)
|
|
84
86
|
params[:system] = params[:messages].shift[:content] if params.dig(:messages, 0, :role) == :system
|
|
85
87
|
params[:messages].pop if params[:messages].last[:content].nil? || params[:messages].last[:content].strip.empty?
|
|
88
|
+
remove_opus_4_7_unsupported_sampling_params(params)
|
|
86
89
|
combine_assistant(params)
|
|
87
90
|
end
|
|
88
91
|
|
|
@@ -111,6 +114,20 @@ module Boxcars
|
|
|
111
114
|
|
|
112
115
|
private
|
|
113
116
|
|
|
117
|
+
def remove_opus_4_7_unsupported_sampling_params(params)
|
|
118
|
+
return params unless opus_4_7_model?(params[:model] || params["model"])
|
|
119
|
+
|
|
120
|
+
OPUS_4_7_UNSUPPORTED_SAMPLING_PARAMS.each do |key|
|
|
121
|
+
params.delete(key)
|
|
122
|
+
params.delete(key.to_s)
|
|
123
|
+
end
|
|
124
|
+
params
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def opus_4_7_model?(model)
|
|
128
|
+
model.to_s.start_with?(OPUS_4_7_MODEL_PREFIX)
|
|
129
|
+
end
|
|
130
|
+
|
|
114
131
|
# Process the raw response from Anthropic API
|
|
115
132
|
def process_anthropic_response(raw_response, response_data)
|
|
116
133
|
normalized_response = normalize_anthropic_payload(raw_response)
|
|
@@ -118,18 +135,21 @@ module Boxcars
|
|
|
118
135
|
response_data[:parsed_json] = normalized_response
|
|
119
136
|
|
|
120
137
|
if normalized_response && !normalized_response["error"]
|
|
121
|
-
response_data[:success] = true
|
|
122
138
|
response_data[:status_code] = 200 # Inferred
|
|
139
|
+
normalize_anthropic_usage!(normalized_response)
|
|
140
|
+
|
|
123
141
|
# Transform response to match expected format
|
|
124
|
-
normalized_response["completion"] = normalized_response
|
|
142
|
+
normalized_response["completion"] = extract_anthropic_completion(normalized_response)
|
|
143
|
+
|
|
144
|
+
if normalized_response["completion"].empty?
|
|
145
|
+
response_data[:success] = false
|
|
146
|
+
response_data[:error] ||= Error.new("Anthropic response contained no text content")
|
|
147
|
+
return
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
response_data[:success] = true
|
|
125
151
|
normalized_response["choices"] ||= [{ "text" => normalized_response["completion"],
|
|
126
152
|
"finish_reason" => normalized_response["stop_reason"] }]
|
|
127
|
-
if normalized_response["usage"].is_a?(Hash)
|
|
128
|
-
normalized_response["usage"]["prompt_tokens"] ||= normalized_response["usage"]["input_tokens"]
|
|
129
|
-
normalized_response["usage"]["completion_tokens"] ||= normalized_response["usage"]["output_tokens"]
|
|
130
|
-
normalized_response["usage"]["total_tokens"] ||= normalized_response["usage"]["prompt_tokens"].to_i +
|
|
131
|
-
normalized_response["usage"]["completion_tokens"].to_i
|
|
132
|
-
end
|
|
133
153
|
normalized_response.delete("content")
|
|
134
154
|
else
|
|
135
155
|
response_data[:success] = false
|
|
@@ -139,6 +159,33 @@ module Boxcars
|
|
|
139
159
|
end
|
|
140
160
|
end
|
|
141
161
|
|
|
162
|
+
def extract_anthropic_completion(normalized_response)
|
|
163
|
+
content = normalized_response["content"]
|
|
164
|
+
blocks = content.is_a?(Array) ? content : [content]
|
|
165
|
+
|
|
166
|
+
blocks.filter_map { |block| extract_anthropic_text_block(block) }.join("\n").strip
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def extract_anthropic_text_block(block)
|
|
170
|
+
case block
|
|
171
|
+
when String
|
|
172
|
+
block
|
|
173
|
+
when Hash
|
|
174
|
+
block["text"] || block[:text]
|
|
175
|
+
else
|
|
176
|
+
block.text if block.respond_to?(:text)
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def normalize_anthropic_usage!(normalized_response)
|
|
181
|
+
return unless normalized_response["usage"].is_a?(Hash)
|
|
182
|
+
|
|
183
|
+
normalized_response["usage"]["prompt_tokens"] ||= normalized_response["usage"]["input_tokens"]
|
|
184
|
+
normalized_response["usage"]["completion_tokens"] ||= normalized_response["usage"]["output_tokens"]
|
|
185
|
+
normalized_response["usage"]["total_tokens"] ||= normalized_response["usage"]["prompt_tokens"].to_i +
|
|
186
|
+
normalized_response["usage"]["completion_tokens"].to_i
|
|
187
|
+
end
|
|
188
|
+
|
|
142
189
|
# Handle errors from Anthropic API calls
|
|
143
190
|
def handle_anthropic_error(error, response_data)
|
|
144
191
|
response_data[:error] = error
|
data/lib/boxcars/version.rb
CHANGED