ace-review 0.53.5 → 0.53.6
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 +5 -0
- data/lib/ace/review/atoms/context_limit_resolver.rb +16 -143
- data/lib/ace/review/molecules/llm_executor.rb +9 -2
- data/lib/ace/review/molecules/multi_model_executor.rb +10 -3
- data/lib/ace/review/molecules/strategies/adaptive_strategy.rb +1 -1
- data/lib/ace/review/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 647741c9f1b7814b5471a9a07c4f1693ac649f953d3f530bae67516a81cd7f0d
|
|
4
|
+
data.tar.gz: 520c59a0dda292b28d383215606fb7463d64d35f3b3ef0c024428243f2dc0870
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cb3239ee728103949252327de0a7b97de54ea1747ca3a8c2c2fd1e930281091bcb57ce14de3ca44041bf2d95d14608883b753f4af2b85f2d4d019fd4829bfb32
|
|
7
|
+
data.tar.gz: 892722919f96459f188ddd278f8d42f0538f81297fd9c87729302ca2072f9c62901f58396a7a17a72bb6c677394eb1f341927c2b3a0d53b199450a8dd845d0a1
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.53.6] - 2026-04-24
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- 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.
|
|
14
|
+
|
|
10
15
|
## [0.53.5] - 2026-04-19
|
|
11
16
|
|
|
12
17
|
### 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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 #{
|
|
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
|
|
18
|
-
|
|
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
|
-
|
|
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.
|
|
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)
|
data/lib/ace/review/version.rb
CHANGED
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.
|
|
4
|
+
version: 0.53.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Michal Czyz
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-04-
|
|
10
|
+
date: 2026-04-27 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ace-support-cli
|