feat: adapt review budget to diff size
This commit is contained in:
@@ -306,6 +306,11 @@ limit, preserves any output already emitted, and records the cap reason in the
|
||||
review body and Langfuse metadata. Environment variables provide deployment-wide
|
||||
defaults; repository budget values override them.
|
||||
|
||||
Without an explicit repository budget, changed diffs receive adaptive headroom:
|
||||
the default 20-step/120K-token budget grows to 40/400K, 60/800K, or 80/1.2M for
|
||||
diffs over 200, 800, or 2,000 changed lines. This keeps focused PRs inexpensive
|
||||
while allowing broad TypeScript/Go reviews to finish. Hard ceilings still apply.
|
||||
|
||||
**Cross-lens dedup:** synthesiser drops duplicates by
|
||||
`sha256[:16](path|line|severity|problem[:80])` (matches the feedback DB's
|
||||
`posthash`), then promotes multi-lens agreement by one severity step
|
||||
|
||||
@@ -15,6 +15,13 @@ DEFAULTS = {
|
||||
"max_duration_seconds": 480,
|
||||
}
|
||||
|
||||
PROFILES = (
|
||||
# (changed lines threshold, steps, total tokens, output tokens, seconds)
|
||||
(2_000, 80, 1_200_000, 80_000, 1_800),
|
||||
(800, 60, 800_000, 60_000, 1_200),
|
||||
(200, 40, 400_000, 40_000, 900),
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class Budget:
|
||||
@@ -63,6 +70,34 @@ class Budget:
|
||||
price_target=price_target,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def for_review(cls, config: dict | None, diff: str) -> "Budget":
|
||||
"""Choose safe headroom from diff size, unless config is explicit."""
|
||||
if isinstance((config or {}).get("budget"), dict):
|
||||
return cls.from_config(config)
|
||||
changed_lines = _changed_line_count(diff)
|
||||
for threshold, steps, tokens, output, seconds in PROFILES:
|
||||
if changed_lines >= threshold:
|
||||
return cls.from_config({
|
||||
**(config or {}),
|
||||
"budget": {
|
||||
"max_steps": steps,
|
||||
"max_total_tokens": tokens,
|
||||
"max_output_tokens": output,
|
||||
"max_duration_seconds": seconds,
|
||||
},
|
||||
})
|
||||
return cls.from_config(config)
|
||||
|
||||
|
||||
def _changed_line_count(diff: str) -> int:
|
||||
"""Count changed lines without treating hunk headers as additions."""
|
||||
return sum(
|
||||
1 for line in diff.splitlines()
|
||||
if (line.startswith("+") and not line.startswith("+++"))
|
||||
or (line.startswith("-") and not line.startswith("---"))
|
||||
)
|
||||
|
||||
|
||||
def _env_int(name: str, default: int) -> int:
|
||||
try:
|
||||
|
||||
@@ -440,7 +440,7 @@ def run_lenses_review(
|
||||
always has: prose + a final ```json fence with the legacy schema).
|
||||
"""
|
||||
os.makedirs(WORK_ROOT, exist_ok=True)
|
||||
budget = budget or Budget.from_config(config)
|
||||
budget = budget or Budget.for_review(config, diff)
|
||||
budget_state = budget_state or BudgetState(budget)
|
||||
workdir = tempfile.mkdtemp(prefix=f"{repo.replace('/', '_')}-{sha[:8]}-", dir=WORK_ROOT)
|
||||
keep = bool(os.environ.get("PRAGENT_KEEP_WORK"))
|
||||
@@ -687,7 +687,7 @@ def run(
|
||||
additional_context=additional_context,
|
||||
)
|
||||
|
||||
budget = Budget.from_config(config)
|
||||
budget = Budget.for_review(config, diff)
|
||||
budget_state = BudgetState(budget)
|
||||
os.makedirs(WORK_ROOT, exist_ok=True)
|
||||
workdir = tempfile.mkdtemp(prefix=f"{repo.replace('/', '_')}-{sha[:8]}-", dir=WORK_ROOT)
|
||||
|
||||
Reference in New Issue
Block a user