ace-review 0.53.5 → 0.53.8

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: c50e105e74afc8802976a5c869debdd9514996f8c5c48c1ff0cc2266f1a2622f
4
- data.tar.gz: 18512f481aa7315c446b7bfb93d7844dde492f1369b3a33cc34c3edb590bb1d0
3
+ metadata.gz: 6a7f852859141beb9f76888aebc74025c5280a2c45c3617fb7fa4dd6cf36aad7
4
+ data.tar.gz: d1e221d3a19a8f72e88d6cfb7543e9e635e15f5a3b7b109b4ed118fcdb93f23f
5
5
  SHA512:
6
- metadata.gz: 1869bc1bcbe622b59b88189ccbaf09192b183b44aac2a10d926b38befbb58f6e01a54601c218234d0e681532d590a4bf2d531d3ca5f027dda17957f19a046270
7
- data.tar.gz: 68f5a18ae201735fb0577235d1a9bc53e703ea2e44c89e927b053e1048fa1bcfb2782facfed324a612b42cc8a07956fd96a99cc18599ebdd3538c86bcccb7105
6
+ metadata.gz: b56f099530dd05c657ecd4611ca1eec58ad65bf11fee2e92e46ea74d243866bb498cdefee3a8baa15e5acbea4f5395a3d0c86bac1b234181e556b3930e204d5a
7
+ data.tar.gz: 87990b255b91465879958f09096a8e64ab1ae320383f90d2083966dc2670103b3cb7c72ce2ffaf255771cb41b78c3c41852f606c911843f4ce2fbf75eed983ad
data/CHANGELOG.md CHANGED
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.53.8] - 2026-08-12
11
+
12
+ ### Technical
13
+ - Raised the `ace-support-core` dependency floor to `~> 0.31` after the principles-first bootstrap guidance release.
14
+ ## [0.53.7] - 2026-08-12
15
+
16
+ ### Technical
17
+ - Aligned gemspec dependency floors with current ACE package minor release lines and safe external minor dependency bumps (no major version jumps).
18
+
19
+ ## [0.53.6] - 2026-04-24
20
+
21
+ ### Fixed
22
+ - Sized review prompts and adaptive review execution against the resolved concrete model target so role and alias-based reviews no longer rely on provider-wide context assumptions.
23
+
10
24
  ## [0.53.5] - 2026-04-19
11
25
 
12
26
  ### Technical
@@ -1,161 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "ace/llm"
4
+
3
5
  module Ace
4
6
  module Review
5
7
  module Atoms
6
- # Pure function for resolving model context limits
7
- #
8
- # Maps model names to their context window sizes. Handles provider prefixes
9
- # (google:, anthropic:, openai:) and uses pattern matching for model families.
10
- #
11
- # Resolution order:
12
- # 1. ace-llm provider config (context_limit in providers/*.yml)
13
- # 2. Hardcoded pattern matching (MODEL_LIMITS)
14
- # 3. Conservative default for unknown models
15
- #
16
- # @example Basic usage
17
- # ContextLimitResolver.resolve("google:gemini-2.5-pro")
18
- # #=> 1_000_000
19
- #
20
- # @example Without provider prefix
21
- # ContextLimitResolver.resolve("claude-3-sonnet")
22
- # #=> 200_000
8
+ # Review-local wrapper around ace-llm's resolved model limit lookup.
23
9
  module ContextLimitResolver
24
- # Conservative default for unknown models
25
- DEFAULT_LIMIT = 200_000
26
-
27
- # Model patterns and their context limits (fallback when ace-llm config unavailable)
28
- # Order matters - first match wins
29
- # Patterns use regex for flexible matching
30
- MODEL_LIMITS = [
31
- # Gemini models
32
- {pattern: /gemini-1\.5-pro/i, limit: 2_000_000},
33
- {pattern: /gemini-1\.5-flash/i, limit: 1_000_000},
34
- {pattern: /gemini-2\.5-pro/i, limit: 1_000_000},
35
- {pattern: /gemini-2\.5-flash/i, limit: 1_000_000},
36
- {pattern: /gemini-2\.0/i, limit: 1_000_000},
37
- # Fallback for any other gemini model
38
- {pattern: /gemini/i, limit: 1_000_000},
39
-
40
- # Claude models (all variants: opus, sonnet, haiku)
41
- {pattern: /claude.*opus/i, limit: 1_000_000},
42
- {pattern: /claude.*sonnet/i, limit: 1_000_000},
43
- {pattern: /claude.*haiku/i, limit: 1_000_000},
44
- # Fallback for any other claude model
45
- {pattern: /claude/i, limit: 1_000_000},
10
+ DEFAULT_LIMIT = Ace::LLM::Molecules::ModelLimitResolver::DEFAULT_CONTEXT_LIMIT
46
11
 
47
- # OpenAI models
48
- {pattern: /gpt-5\.\d/i, limit: 1_050_000},
49
- {pattern: /o4-/i, limit: 1_050_000},
50
- {pattern: /gpt-4o/i, limit: 128_000},
51
- {pattern: /gpt-4-turbo/i, limit: 128_000},
52
- {pattern: /gpt-4-32k/i, limit: 32_768},
53
- {pattern: /gpt-4-\d+-preview/i, limit: 128_000}, # gpt-4-1106-preview, gpt-4-0125-preview
54
- {pattern: /gpt-4-\d+$/i, limit: 8_192}, # legacy gpt-4-0613, etc.
55
- {pattern: /gpt-4$/i, limit: 8_192}, # base gpt-4 model
56
- {pattern: /o1-/i, limit: 200_000},
57
- {pattern: /o3-/i, limit: 200_000}
58
- ].freeze
59
-
60
- # Resolve context limit for a model
61
- #
62
- # Resolution order:
63
- # 1. ace-llm provider config (if available and provider specified)
64
- # 2. Hardcoded pattern matching
65
- # 3. Default limit
66
- #
67
- # @param model_name [String, nil] Model identifier, optionally with provider prefix
68
- # @return [Integer] Context limit in tokens
69
- #
70
- # @example With provider prefix
71
- # ContextLimitResolver.resolve("google:gemini-2.5-pro")
72
- # #=> 1_000_000
73
- #
74
- # @example Without provider prefix
75
- # ContextLimitResolver.resolve("claude-3-opus")
76
- # #=> 200_000
77
- #
78
- # @example Unknown model
79
- # ContextLimitResolver.resolve("unknown-model")
80
- # #=> 128_000
81
12
  def self.resolve(model_name)
82
- return DEFAULT_LIMIT if model_name.nil? || model_name.empty?
83
-
84
- # Try to get limit from ace-llm provider config first
85
- limit = load_from_ace_llm(model_name)
86
- return limit if limit
87
-
88
- # Fall back to hardcoded pattern matching
89
- normalized = strip_provider_prefix(model_name)
90
- match = MODEL_LIMITS.find { |entry| normalized.match?(entry[:pattern]) }
91
- match ? match[:limit] : DEFAULT_LIMIT
13
+ resolve_details(model_name).context_limit
92
14
  end
93
15
 
94
- # Get the default limit for unknown models
95
- #
96
- # @return [Integer] Default context limit
97
- def self.default_limit
98
- DEFAULT_LIMIT
99
- end
100
-
101
- # Load context limit from ace-llm provider configuration
102
- #
103
- # @param model_name [String] Model identifier with provider prefix
104
- # @return [Integer, nil] Context limit from config, or nil if not found
105
- def self.load_from_ace_llm(model_name)
106
- # Extract provider prefix (e.g., "google" from "google:gemini-2.5-pro")
107
- return nil unless model_name.include?(":")
108
-
109
- provider = model_name.split(":").first
110
- return nil if provider.nil? || provider.empty?
111
-
112
- # Try to load provider config via ace-llm
113
- config = load_provider_config(provider)
114
- return nil unless config
115
-
116
- # Get context_limit from provider config
117
- limit = config["context_limit"]
118
- limit.is_a?(Integer) ? limit : nil
16
+ def self.resolve_details(model_name)
17
+ Ace::LLM::Molecules::ModelLimitResolver.resolve(model_name)
119
18
  rescue
120
- nil # Fall back to hardcoded on any error
121
- end
122
- private_class_method :load_from_ace_llm
123
-
124
- # Load provider configuration from ace-llm
125
- #
126
- # @param provider [String] Provider name (e.g., "google", "anthropic")
127
- # @return [Hash, nil] Provider config hash or nil
128
- def self.load_provider_config(provider)
129
- # Try to use ace-llm's config loader if available
130
- return nil unless defined?(Ace::LLM::Molecules::ConfigLoader)
131
-
132
- resolver = Ace::Support::Config.create(
133
- config_dir: ".ace",
134
- defaults_dir: ".ace-defaults",
135
- gem_path: Ace::LLM::Molecules::ConfigLoader.gem_root
19
+ Ace::LLM::Molecules::ModelLimitResolver::ResolveResult.new(
20
+ provider: nil,
21
+ model: nil,
22
+ context_limit: DEFAULT_LIMIT,
23
+ output_limit: nil,
24
+ source: :fallback,
25
+ original_target: model_name.to_s
136
26
  )
137
-
138
- config = resolver.resolve_namespace("llm", filename: "providers/#{provider}")
139
- config.to_h
140
- rescue
141
- nil
142
27
  end
143
- private_class_method :load_provider_config
144
28
 
145
- # Strip provider prefix from model name
146
- #
147
- # @param model_name [String] Model identifier
148
- # @return [String] Model name without provider prefix
149
- #
150
- # @example
151
- # strip_provider_prefix("google:gemini-2.5-pro")
152
- # #=> "gemini-2.5-pro"
153
- def self.strip_provider_prefix(model_name)
154
- # Common provider prefixes
155
- model_name.sub(/\A(google|anthropic|openai|codex|cli):/, "")
29
+ def self.default_limit
30
+ DEFAULT_LIMIT
156
31
  end
157
-
158
- private_class_method :strip_provider_prefix
159
32
  end
160
33
  end
161
34
  end
@@ -67,12 +67,19 @@ module Ace
67
67
  total_chars = (system_prompt&.length || 0) + (user_prompt&.length || 0)
68
68
  estimated_tokens = total_chars / 4 # Rough estimate: 4 chars per token
69
69
 
70
- context_limit = Ace::Review::Atoms::ContextLimitResolver.resolve(model)
70
+ limit_details = Ace::Review::Atoms::ContextLimitResolver.resolve_details(model)
71
+ context_limit = limit_details.context_limit
71
72
  threshold = (context_limit * PROMPT_SIZE_WARNING_RATIO).to_i
72
73
  return unless estimated_tokens > threshold
73
74
 
75
+ display_model = if limit_details.full_model && limit_details.full_model != model
76
+ "#{model} -> #{limit_details.full_model}"
77
+ else
78
+ model
79
+ end
80
+
74
81
  warn "Warning: Prompt size (~#{estimated_tokens.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,')} tokens) " \
75
- "may exceed #{model} context limit (#{context_limit.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,')} tokens)"
82
+ "may exceed #{display_model} context limit (#{context_limit.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,')} tokens)"
76
83
  end
77
84
 
78
85
  # Check if Ruby API is available
@@ -14,8 +14,8 @@ module Ace
14
14
  # Default timeout for LLM queries (5 minutes)
15
15
  DEFAULT_LLM_TIMEOUT = 300
16
16
 
17
- # Warning threshold: 80% of typical 1M context window
18
- PROMPT_SIZE_WARNING_THRESHOLD = 800_000
17
+ # Warning threshold: 80% of the smallest resolved context window in the batch
18
+ PROMPT_SIZE_WARNING_RATIO = LlmExecutor::PROMPT_SIZE_WARNING_RATIO
19
19
 
20
20
  def initialize(max_concurrent: nil, llm_timeout: nil)
21
21
  # Read from config, fallback to default of 3, clamp to minimum 1
@@ -266,7 +266,14 @@ module Ace
266
266
  total_chars = (system_prompt&.length || 0) + (user_prompt&.length || 0)
267
267
  estimated_tokens = total_chars / 4 # Rough estimate: 4 chars per token
268
268
 
269
- return unless estimated_tokens > PROMPT_SIZE_WARNING_THRESHOLD
269
+ resolved_limits = models.map do |model|
270
+ Atoms::ContextLimitResolver.resolve_details(model)
271
+ end
272
+ min_context_limit = resolved_limits.map(&:context_limit).compact.min
273
+ return if min_context_limit.nil?
274
+
275
+ threshold = (min_context_limit * PROMPT_SIZE_WARNING_RATIO).to_i
276
+ return unless estimated_tokens > threshold
270
277
 
271
278
  model_list = models.join(", ")
272
279
  warn "Warning: Prompt size (~#{estimated_tokens.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, '\\1,')} tokens) " \
@@ -70,7 +70,7 @@ module Ace
70
70
  explicit_limit = context[:model_context_limit] || context["model_context_limit"]
71
71
 
72
72
  # Resolve model context limit
73
- model_limit = explicit_limit || Atoms::ContextLimitResolver.resolve(model)
73
+ model_limit = explicit_limit || Atoms::ContextLimitResolver.resolve_details(model).context_limit
74
74
 
75
75
  # Select and delegate to appropriate strategy
76
76
  selected = select_strategy(subject, model_limit, model)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ace
4
4
  module Review
5
- VERSION = '0.53.5'
5
+ VERSION = "0.53.8"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-review
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.53.5
4
+ version: 0.53.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-04-20 00:00:00.000000000 Z
10
+ date: 2026-08-12 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: ace-support-cli
@@ -29,126 +29,126 @@ dependencies:
29
29
  requirements:
30
30
  - - "~>"
31
31
  - !ruby/object:Gem::Version
32
- version: '0.9'
32
+ version: '0.17'
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '0.9'
39
+ version: '0.17'
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: ace-b36ts
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '0.13'
46
+ version: '0.14'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '0.13'
53
+ version: '0.14'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: ace-support-core
56
56
  requirement: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '0.29'
60
+ version: '0.31'
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - "~>"
66
66
  - !ruby/object:Gem::Version
67
- version: '0.29'
67
+ version: '0.31'
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: ace-bundle
70
70
  requirement: !ruby/object:Gem::Requirement
71
71
  requirements:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
- version: '0.41'
74
+ version: '0.43'
75
75
  type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '0.41'
81
+ version: '0.43'
82
82
  - !ruby/object:Gem::Dependency
83
83
  name: ace-git
84
84
  requirement: !ruby/object:Gem::Requirement
85
85
  requirements:
86
86
  - - "~>"
87
87
  - !ruby/object:Gem::Version
88
- version: '0.19'
88
+ version: '0.22'
89
89
  type: :runtime
90
90
  prerelease: false
91
91
  version_requirements: !ruby/object:Gem::Requirement
92
92
  requirements:
93
93
  - - "~>"
94
94
  - !ruby/object:Gem::Version
95
- version: '0.19'
95
+ version: '0.22'
96
96
  - !ruby/object:Gem::Dependency
97
97
  name: ace-support-nav
98
98
  requirement: !ruby/object:Gem::Requirement
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '0.25'
102
+ version: '0.28'
103
103
  type: :runtime
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '0.25'
109
+ version: '0.28'
110
110
  - !ruby/object:Gem::Dependency
111
111
  name: ace-llm
112
112
  requirement: !ruby/object:Gem::Requirement
113
113
  requirements:
114
114
  - - "~>"
115
115
  - !ruby/object:Gem::Version
116
- version: '0.30'
116
+ version: '0.38'
117
117
  type: :runtime
118
118
  prerelease: false
119
119
  version_requirements: !ruby/object:Gem::Requirement
120
120
  requirements:
121
121
  - - "~>"
122
122
  - !ruby/object:Gem::Version
123
- version: '0.30'
123
+ version: '0.38'
124
124
  - !ruby/object:Gem::Dependency
125
125
  name: ace-task
126
126
  requirement: !ruby/object:Gem::Requirement
127
127
  requirements:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
- version: '0.31'
130
+ version: '0.37'
131
131
  type: :runtime
132
132
  prerelease: false
133
133
  version_requirements: !ruby/object:Gem::Requirement
134
134
  requirements:
135
135
  - - "~>"
136
136
  - !ruby/object:Gem::Version
137
- version: '0.31'
137
+ version: '0.37'
138
138
  - !ruby/object:Gem::Dependency
139
139
  name: ace-support-test-helpers
140
140
  requirement: !ruby/object:Gem::Requirement
141
141
  requirements:
142
142
  - - "~>"
143
143
  - !ruby/object:Gem::Version
144
- version: '0.13'
144
+ version: '0.14'
145
145
  type: :development
146
146
  prerelease: false
147
147
  version_requirements: !ruby/object:Gem::Requirement
148
148
  requirements:
149
149
  - - "~>"
150
150
  - !ruby/object:Gem::Version
151
- version: '0.13'
151
+ version: '0.14'
152
152
  - !ruby/object:Gem::Dependency
153
153
  name: bundler
154
154
  requirement: !ruby/object:Gem::Requirement
@@ -197,14 +197,14 @@ dependencies:
197
197
  requirements:
198
198
  - - "~>"
199
199
  - !ruby/object:Gem::Version
200
- version: '1.21'
200
+ version: '1.88'
201
201
  type: :development
202
202
  prerelease: false
203
203
  version_requirements: !ruby/object:Gem::Requirement
204
204
  requirements:
205
205
  - - "~>"
206
206
  - !ruby/object:Gem::Version
207
- version: '1.21'
207
+ version: '1.88'
208
208
  description: Run focused, repeatable code reviews using configurable presets and multiple
209
209
  LLM models in parallel. Findings become trackable feedback items with a verify-apply-resolve
210
210
  lifecycle.