ruby_llm-contract 0.5.2 → 0.6.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.
@@ -9,13 +9,13 @@ module RubyLLM
9
9
  DEFAULT_RETRY_ON = %i[validation_failed parse_error adapter_error].freeze
10
10
 
11
11
  def initialize(models: nil, attempts: nil, retry_on: nil, &block)
12
- @models = []
12
+ @configs = []
13
13
  @retryable_statuses = DEFAULT_RETRY_ON.dup
14
14
 
15
15
  if block
16
16
  @max_attempts = 1
17
17
  instance_eval(&block)
18
- warn_no_retry! if @max_attempts == 1 && @models.empty?
18
+ warn_no_retry! if @max_attempts == 1 && @configs.empty?
19
19
  else
20
20
  apply_keywords(models: models, attempts: attempts, retry_on: retry_on)
21
21
  end
@@ -28,14 +28,18 @@ module RubyLLM
28
28
  validate_max_attempts!
29
29
  end
30
30
 
31
- def escalate(*model_list)
32
- @models = model_list.flatten
33
- @max_attempts = @models.length if @max_attempts < @models.length
31
+ def escalate(*config_list)
32
+ @configs = config_list.flatten.map { |c| normalize_config(c).freeze }.freeze
33
+ @max_attempts = @configs.length if @max_attempts < @configs.length
34
34
  end
35
35
  alias models escalate
36
36
 
37
37
  def model_list
38
- @models
38
+ @configs.map { |c| c[:model] }.freeze
39
+ end
40
+
41
+ def config_list
42
+ @configs
39
43
  end
40
44
 
41
45
  def retry_on(*statuses)
@@ -46,29 +50,38 @@ module RubyLLM
46
50
  retryable_statuses.include?(result.status)
47
51
  end
48
52
 
49
- def model_for_attempt(attempt, default_model)
50
- if @models.any?
51
- @models[attempt] || @models.last
53
+ def config_for_attempt(attempt, default_config)
54
+ if @configs.any?
55
+ @configs[attempt] || @configs.last
52
56
  else
53
- default_model
57
+ default_config
54
58
  end
55
59
  end
56
60
 
61
+ def model_for_attempt(attempt, default_model)
62
+ config_for_attempt(attempt, { model: default_model })[:model]
63
+ end
64
+
57
65
  private
58
66
 
59
67
  def apply_keywords(models:, attempts:, retry_on:)
60
68
  if models
61
- @models = Array(models).dup.freeze
62
- @max_attempts = @models.length
69
+ @configs = Array(models).map { |m| normalize_config(m).freeze }.freeze
70
+ @max_attempts = @configs.length
63
71
  else
64
72
  @max_attempts = attempts || 1
65
73
  end
66
74
  @retryable_statuses = Array(retry_on).dup if retry_on
67
75
  end
68
76
 
77
+ def normalize_config(entry)
78
+ RubyLLM::Contract.normalize_candidate_config(entry)
79
+ end
80
+
69
81
  def warn_no_retry!
70
- warn "[ruby_llm-contract] retry_policy has max_attempts=1 with no models. " \
71
- "This means no actual retry will happen. Add `attempts 2` or `escalate %w[model1 model2]`."
82
+ warn "[ruby_llm-contract] retry_policy has max_attempts=1 with no configs. " \
83
+ "This means no actual retry will happen. Add `attempts 2` or " \
84
+ '`escalate "model1", "model2"`.'
72
85
  end
73
86
 
74
87
  def validate_max_attempts!
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RubyLLM
4
4
  module Contract
5
- VERSION = "0.5.2"
5
+ VERSION = "0.6.2"
6
6
  end
7
7
  end
@@ -78,6 +78,27 @@ module RubyLLM
78
78
  Thread.current[:ruby_llm_contract_reloading] = false
79
79
  end
80
80
 
81
+ def normalize_candidate_config(entry)
82
+ case entry
83
+ when String
84
+ raise ArgumentError, "Candidate model must be a non-empty String" if entry.strip.empty?
85
+
86
+ { model: entry.strip }
87
+ when Hash
88
+ model = entry[:model] || entry["model"]
89
+ unless model.is_a?(String) && !model.strip.empty?
90
+ raise ArgumentError, "Candidate config must include a non-empty String :model"
91
+ end
92
+
93
+ normalized = { model: model.strip }
94
+ effort = entry[:reasoning_effort] || entry["reasoning_effort"]
95
+ normalized[:reasoning_effort] = effort if effort
96
+ normalized
97
+ else
98
+ raise ArgumentError, "Expected String or Hash, got #{entry.class}"
99
+ end
100
+ end
101
+
81
102
  private
82
103
 
83
104
  # Filter stale hosts, deduplicate by name (last wins), prune registry in-place
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.5.2
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justyna
@@ -130,10 +130,13 @@ files:
130
130
  - lib/ruby_llm/contract/eval/prompt_diff_comparator.rb
131
131
  - lib/ruby_llm/contract/eval/prompt_diff_presenter.rb
132
132
  - lib/ruby_llm/contract/eval/prompt_diff_serializer.rb
133
+ - lib/ruby_llm/contract/eval/recommendation.rb
134
+ - lib/ruby_llm/contract/eval/recommender.rb
133
135
  - lib/ruby_llm/contract/eval/report.rb
134
136
  - lib/ruby_llm/contract/eval/report_presenter.rb
135
137
  - lib/ruby_llm/contract/eval/report_stats.rb
136
138
  - lib/ruby_llm/contract/eval/report_storage.rb
139
+ - lib/ruby_llm/contract/eval/retry_optimizer.rb
137
140
  - lib/ruby_llm/contract/eval/runner.rb
138
141
  - lib/ruby_llm/contract/eval/step_expectation_applier.rb
139
142
  - lib/ruby_llm/contract/eval/step_result_normalizer.rb