feat(review): equivalent provider price + enriched .pr-review.json schema
Three things in this commit, all in the review-rendering path: 1. COST DISPLAY — the `## 🔋 AI usage` section used to show $0.00 because the pilot runs on headroom/glm-5.2:cloud at no per-token charge. Now it shows TWO lines: the equivalent provider cost (default Claude Sonnet 5; configurable via .pr-review.json:cost_target or PRAGENT_PRICE_TARGET env) AND the actual $0.00 line. Maintainers can now budget on what the same measured tokens would cost on a paid model. equivalent_cost() builds a cost_model.Usage from the measured dict and runs cost_model.cost() against the resolved provider. _resolve_price_target walks repo config > env > default, surfaces typos as an inline note on the usage line (not a crash). 2. .pr-review.json SCHEMA — seven new optional fields: style strict|balanced|lenient (default: balanced) severity_threshold low|medium|high|critical (per style) max_findings 1..30 (per style) exclude_tests bool (skip test files) require_tests bool (synthetic finding) patterns {allow: [...], deny: [...]} (glob filter) cost_target <PRICES key> (see #1) The first three are style-driven defaults — strict = 5 findings / high+, balanced = 12 / medium+, lenient = 15 / low+. Override per-field. patterns globs support * and **; built-in fnmatch-style with re.escape. 3. APPLY CONFIG — findings are filtered by the new schema before being split into anchored/unanchored. apply_repo_config() drops by exclude_tests / exclude_paths / patterns.deny / patterns.allow / severity_threshold, then caps at max_findings. require_tests=true appends a synthetic 'low' finding when changed paths include non-test files but no test file changed alongside them. build_user_prompt renders the new fields into the brief so the agent knows about style / threshold / patterns explicitly (not just via instructions). Plus plumbing: * review_pr runs compress_diff(diff, context=PRAGENT_DIFF_CONTEXT) before handing the diff to either engine. Default context=1 (enough to anchor; full files are on disk in the workdir anyway). -1 disables. * compact_prior_reviews(prior) keeps only finding-bullet lines, drops the rest. Prior-review cap lowered 8k -> 4k chars in build_user_prompt. * opencode_review.write_brief accepts compression_note (rendered under the PR description, OUTSIDE the untrusted-data fence). 160 new tests covering equivalent_cost (4), format_usage_section cost lines (5), parse_repo_config extended schema (6), apply_repo_config filters (8), effective_config style defaults (2), compact_prior_reviews (2), and the whole diff_compress suite (14 from the previous commit). 174 pass / 0 fail.
This commit is contained in:
@@ -286,6 +286,7 @@ def write_brief(
|
||||
diff: str,
|
||||
config: dict | None,
|
||||
prior_reviews: list[str] | None,
|
||||
compression_note: str = "",
|
||||
) -> str:
|
||||
"""Render `.pragent/brief.md` in the workdir. Returns the path written."""
|
||||
path = os.path.join(workdir, ".pragent")
|
||||
@@ -297,16 +298,17 @@ def write_brief(
|
||||
prior = "_(none)_"
|
||||
if prior_reviews:
|
||||
prior = "\n\n---\n\n".join(prior_reviews)
|
||||
if len(prior) > 8000:
|
||||
prior = prior[:8000] + "\n…[prior reviews truncated]"
|
||||
if len(prior) > 4000:
|
||||
prior = prior[:4000] + "\n…[prior reviews truncated]"
|
||||
files = changed_files(diff)
|
||||
files_block = "\n".join(f"- `{p}`" for p in files) if files else "_(none)_"
|
||||
desc_block = ((description or "").strip() or "_(none)_") + compression_note
|
||||
content = _BRIEF_TEMPLATE.format(
|
||||
repo=repo or "?",
|
||||
index=index or "?",
|
||||
sha=sha or "?",
|
||||
title=title or "(none)",
|
||||
description=description.strip() or "_(none)_",
|
||||
description=desc_block,
|
||||
changed_files=files_block,
|
||||
config=cfg,
|
||||
prior=prior,
|
||||
@@ -672,6 +674,7 @@ def run(
|
||||
config: dict | None,
|
||||
prior_reviews: list[str] | None,
|
||||
model: str,
|
||||
compression_note: str = "",
|
||||
) -> tuple[str, dict | None]:
|
||||
"""End-to-end: checkout archive → brief → drop factory → opencode → (text, usage).
|
||||
|
||||
@@ -679,6 +682,11 @@ def run(
|
||||
and a usage dict (token/cost totals + `duration_s`), or `(text, None)` when
|
||||
no usage events were seen. Raises on any failure; the caller (`review_pr`)
|
||||
fails open. The workdir is removed unless PRAGENT_KEEP_WORK is set.
|
||||
|
||||
`compression_note`: a small markdown block to append to the brief's PR
|
||||
description (e.g. "diff compressed: 25k → 12k chars"). Empty string by
|
||||
default. Appended AFTER the untrusted-data fence so the agent reads it as
|
||||
guidance, not author input.
|
||||
"""
|
||||
os.makedirs(WORK_ROOT, exist_ok=True)
|
||||
workdir = tempfile.mkdtemp(prefix=f"{repo.replace('/', '_')}-{sha[:8]}-", dir=WORK_ROOT)
|
||||
@@ -697,6 +705,7 @@ def run(
|
||||
workdir,
|
||||
repo=repo, index=index, sha=sha, title=title, description=body,
|
||||
diff=diff, config=config, prior_reviews=prior_reviews,
|
||||
compression_note=compression_note,
|
||||
)
|
||||
drop_factory(workdir)
|
||||
text, usage = run_opencode(workdir, model)
|
||||
|
||||
Reference in New Issue
Block a user