ruby_llm-contract 0.6.4 → 0.7.0
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 +27 -0
- data/Gemfile.lock +2 -2
- data/lib/ruby_llm/contract/step/adapter_caller.rb +19 -2
- data/lib/ruby_llm/contract/step/retry_policy.rb +8 -1
- data/lib/ruby_llm/contract/version.rb +1 -1
- data/ruby_llm-contract.gemspec +35 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5decfb7456338baa05d0e6bb79287bb3fb3af0e0cc2c3f001e09122fa76ac298
|
|
4
|
+
data.tar.gz: be3b46ff015fd651e885c4c078dbdaf06623865f4e4b80b864b66e8dd9e16c34
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd3882613ac2b500c46dc6b1084d8f298db96800bf01932e3bc2638a7a3d2a8588610c1de8a1f3754a8e15fb7b1ef29c0c0a7bddd11709cd95bbf12fcd48e83e
|
|
7
|
+
data.tar.gz: 4cb584323a5575de4131b0eb82cdb1426743ca6651030708673d17264c9fec60619bb7d5d54f62eee4c1fa357b4022f57bf08b95d81f153eccf8e625ce3ef5e7
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.0 (2026-04-21)
|
|
4
|
+
|
|
5
|
+
### Breaking changes
|
|
6
|
+
|
|
7
|
+
- **`:adapter_error` removed from `DEFAULT_RETRY_ON`.** New default: `[:validation_failed, :parse_error]`. `ruby_llm` already retries transport errors (`RateLimitError`, `ServerError`, `ServiceUnavailableError`, `OverloadedError`, timeouts) at the Faraday layer, so the previous default re-ran the same model on errors the HTTP middleware already retried with backoff. To restore pre-0.7 behavior: `retry_on :validation_failed, :parse_error, :adapter_error`. Recommended pattern: pair `:adapter_error` with `escalate "model_a", "model_b"` — a different model/provider can bypass what transport retry could not.
|
|
8
|
+
- **`AdapterCaller` narrows `rescue` from `StandardError` to `RubyLLM::Error` + `Faraday::Error`.** Provider errors and transport errors that escape ruby_llm's Faraday retry middleware (`Faraday::TimeoutError`, `Faraday::ConnectionFailed`) still produce `:adapter_error` as before. Programmer errors that are neither (`NoMethodError`, adapter code bugs) now propagate instead of being silently converted to `:adapter_error` and retried. **Known limitation:** adapter code raising `ArgumentError` is still coerced into `:input_error` by `Step::Base#run_once` (which rescues `ArgumentError` for input-type validation). Disambiguating adapter-ArgumentError vs input-validation-ArgumentError requires a `run_once` refactor and is tracked as a follow-up.
|
|
9
|
+
|
|
10
|
+
### Migration
|
|
11
|
+
|
|
12
|
+
If you rely on the old behavior, opt in explicitly:
|
|
13
|
+
|
|
14
|
+
```ruby
|
|
15
|
+
retry_policy do
|
|
16
|
+
attempts 3
|
|
17
|
+
retry_on :validation_failed, :parse_error, :adapter_error
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Or better, with a model fallback chain:
|
|
22
|
+
|
|
23
|
+
```ruby
|
|
24
|
+
retry_policy do
|
|
25
|
+
escalate "gpt-4.1-nano", "gpt-4.1-mini"
|
|
26
|
+
retry_on :validation_failed, :parse_error, :adapter_error
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
3
30
|
## 0.6.4 (2026-04-20)
|
|
4
31
|
|
|
5
32
|
### Features
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
ruby_llm-contract (0.
|
|
4
|
+
ruby_llm-contract (0.7.0)
|
|
5
5
|
dry-types (~> 1.7)
|
|
6
6
|
ruby_llm (~> 1.0)
|
|
7
7
|
ruby_llm-schema (~> 0.3)
|
|
@@ -258,7 +258,7 @@ CHECKSUMS
|
|
|
258
258
|
rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
|
|
259
259
|
ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
|
|
260
260
|
ruby_llm (1.14.0) sha256=57c6f7034fc4a44504ea137d70f853b07824f1c1cdbe774ab3ab3522e7098deb
|
|
261
|
-
ruby_llm-contract (0.
|
|
261
|
+
ruby_llm-contract (0.7.0)
|
|
262
262
|
ruby_llm-schema (0.3.0) sha256=a591edc5ca1b7f0304f0e2261de61ba4b3bea17be09f5cf7558153adfda3dec6
|
|
263
263
|
ruby_parser (3.22.0) sha256=1eb4937cd9eb220aa2d194e352a24dba90aef00751e24c8dfffdb14000f15d23
|
|
264
264
|
rubycritic (4.12.0) sha256=024fed90fe656fa939f6ea80aab17569699ac3863d0b52fd72cb99892247abc8
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "faraday"
|
|
4
|
+
|
|
3
5
|
module RubyLLM
|
|
4
6
|
module Contract
|
|
5
7
|
module Step
|
|
6
8
|
class AdapterCaller
|
|
9
|
+
# Exceptions treated as :adapter_error (retryable when explicitly opted in).
|
|
10
|
+
# RubyLLM::Error covers provider-semantic errors (auth, bad request,
|
|
11
|
+
# rate limit, server error, context length). Faraday::Error covers
|
|
12
|
+
# transport failures that escape ruby_llm's Faraday retry middleware
|
|
13
|
+
# after exhaustion (Faraday::TimeoutError, Faraday::ConnectionFailed).
|
|
14
|
+
# Anything else (NoMethodError, programmer ArgumentError from adapter
|
|
15
|
+
# code, etc.) propagates — those are bugs, not retry candidates.
|
|
16
|
+
ADAPTER_ERRORS = [::RubyLLM::Error, ::Faraday::Error].freeze
|
|
17
|
+
|
|
7
18
|
def initialize(adapter:, adapter_options:)
|
|
8
19
|
@adapter = adapter
|
|
9
20
|
@adapter_options = adapter_options
|
|
@@ -14,8 +25,14 @@ module RubyLLM
|
|
|
14
25
|
response = @adapter.call(messages: messages, **@adapter_options)
|
|
15
26
|
latency_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) * 1000).round
|
|
16
27
|
[response, latency_ms]
|
|
17
|
-
rescue
|
|
18
|
-
|
|
28
|
+
rescue *ADAPTER_ERRORS => e
|
|
29
|
+
result = Result.new(
|
|
30
|
+
status: :adapter_error,
|
|
31
|
+
raw_output: nil,
|
|
32
|
+
parsed_output: nil,
|
|
33
|
+
validation_errors: [e.message]
|
|
34
|
+
)
|
|
35
|
+
[result, 0]
|
|
19
36
|
end
|
|
20
37
|
end
|
|
21
38
|
end
|
|
@@ -6,7 +6,14 @@ module RubyLLM
|
|
|
6
6
|
class RetryPolicy
|
|
7
7
|
attr_reader :max_attempts, :retryable_statuses
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
# Breaking (0.7.0): :adapter_error removed from defaults. ruby_llm's Faraday
|
|
10
|
+
# middleware already retries transport errors (RateLimitError, ServerError,
|
|
11
|
+
# ServiceUnavailableError, OverloadedError, timeouts). Retrying on
|
|
12
|
+
# :adapter_error against the same model re-runs what transport already did.
|
|
13
|
+
# Opt in explicitly with `retry_on :adapter_error` — only meaningful paired
|
|
14
|
+
# with `escalate "model_a", "model_b"` (a different model may bypass what
|
|
15
|
+
# transport retry could not).
|
|
16
|
+
DEFAULT_RETRY_ON = %i[validation_failed parse_error].freeze
|
|
10
17
|
|
|
11
18
|
def initialize(models: nil, attempts: nil, retry_on: nil, &block)
|
|
12
19
|
@configs = []
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "lib/ruby_llm/contract/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = "ruby_llm-contract"
|
|
7
|
+
spec.version = RubyLLM::Contract::VERSION
|
|
8
|
+
spec.authors = ["Justyna"]
|
|
9
|
+
|
|
10
|
+
spec.summary = "Know which LLM model to use, what it costs, and when accuracy drops"
|
|
11
|
+
spec.description = "Compare LLM models by accuracy and cost. Regression-test prompts in CI. " \
|
|
12
|
+
"Start on nano, auto-escalate to bigger models when quality drops. " \
|
|
13
|
+
"Companion gem for ruby_llm."
|
|
14
|
+
spec.homepage = "https://github.com/justi/ruby_llm-contract"
|
|
15
|
+
spec.license = "MIT"
|
|
16
|
+
spec.required_ruby_version = ">= 3.2.0"
|
|
17
|
+
|
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
|
20
|
+
spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
|
21
|
+
spec.metadata["documentation_uri"] = "#{spec.homepage}#readme"
|
|
22
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
|
23
|
+
|
|
24
|
+
spec.files = Dir.chdir(__dir__) do
|
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
|
26
|
+
(File.expand_path(f) == __FILE__) ||
|
|
27
|
+
f.start_with?("spec/", "docs/", "doc/", ".ai/", ".claude/", ".git")
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
spec.require_paths = ["lib"]
|
|
31
|
+
|
|
32
|
+
spec.add_dependency "dry-types", "~> 1.7"
|
|
33
|
+
spec.add_dependency "ruby_llm", "~> 1.0"
|
|
34
|
+
spec.add_dependency "ruby_llm-schema", "~> 0.3"
|
|
35
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_llm-contract
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justyna
|
|
@@ -182,6 +182,7 @@ files:
|
|
|
182
182
|
- lib/ruby_llm/contract/token_estimator.rb
|
|
183
183
|
- lib/ruby_llm/contract/types.rb
|
|
184
184
|
- lib/ruby_llm/contract/version.rb
|
|
185
|
+
- ruby_llm-contract.gemspec
|
|
185
186
|
homepage: https://github.com/justi/ruby_llm-contract
|
|
186
187
|
licenses:
|
|
187
188
|
- MIT
|