Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/agent-review-runtime-quality-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,15 @@ on:
- "scripts/ci/zdr_policy.py"
- "scripts/ci/contextual_orchestrator_review_policy.py"
- "scripts/ci/contextual_orchestrator_review_launcher.py"
- "scripts/ci/noema_review_gate.py"
- "scripts/ci/personal_review_route.py"
- "scripts/ci/contextual_orchestrator_review_sidecar.sh"
- "tests/test_zdr_policy.py"
- "tests/test_contextual_orchestrator_review_policy.py"
- "tests/test_contextual_orchestrator_review_launcher.py"
- "tests/test_review_auto_route.py"
- "tests/test_personal_review_route.py"
- "tests/test_noema_complete_auto_input.py"
- "tests/test_tokyo_review_consumer.py"
- "tests/test_review_auto_cost_admission.py"
- "tests/test_review_ai_app_independence.py"
Expand Down Expand Up @@ -221,6 +223,10 @@ jobs:
noema_suite=true
review_repair_suite=true
;;
scripts/ci/noema_review_gate.py)
noema_suite=true
review_repair_suite=true
;;
.github/workflows/noema-review.yml|\
.github/actions/noema-review/two_phase.py|\
tests/test_noema_reviewer_token_lifetime.py|\
Expand Down Expand Up @@ -304,6 +310,7 @@ jobs:
tests/test_contextual_orchestrator_review_launcher.py|\
tests/test_review_auto_route.py|\
tests/test_personal_review_route.py|\
tests/test_noema_complete_auto_input.py|\
tests/test_tokyo_review_consumer.py|\
tests/test_review_auto_cost_admission.py|\
tests/test_review_ai_app_independence.py|\
Expand Down Expand Up @@ -504,6 +511,7 @@ jobs:
tests/test_contextual_orchestrator_review_launcher.py \
tests/test_review_auto_route.py \
tests/test_personal_review_route.py \
tests/test_noema_complete_auto_input.py \
tests/test_tokyo_review_consumer.py \
tests/test_review_auto_cost_admission.py \
tests/test_review_ai_app_independence.py \
Expand Down Expand Up @@ -550,6 +558,7 @@ jobs:
tests/test_contextual_orchestrator_review_launcher.py \
tests/test_review_auto_route.py \
tests/test_personal_review_route.py \
tests/test_noema_complete_auto_input.py \
tests/test_tokyo_review_consumer.py \
tests/test_review_auto_cost_admission.py \
tests/test_review_ai_app_independence.py \
Expand Down
30 changes: 28 additions & 2 deletions scripts/ci/noema_review_gate.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,20 @@
# noema_review_handoff.py.
NOEMA_REVIEW_BODY_HEAD_RE = re.compile(r"^- Head SHA:\s*`([0-9a-fA-F]{40})`$", re.MULTILINE)
MAX_DIFF_CHARS = 60000
# Personal auto advertises 500,000 input tokens. Bound the complete JSON
# request conservatively by UTF-8 bytes (including schema/envelope), reserving
# 8,192 for chat framing. Do not apply this route's capacity to other models.
MAX_AUTO_REVIEW_REQUEST_BYTES = 500000 - 8192


def complete_auto_input() -> bool:
"""Select only the existing personal-auto endpoint, not arbitrary aliases."""
return (
os.environ.get("NOEMA_LLM_MODEL", "").strip() == "auto"
and os.environ.get("NOEMA_LLM_API_URL", "").strip()
== "https://litellm.poinnetworks.net/v1/chat/completions"
)

MAX_CONTEXT_FILES = 12
MAX_FILE_CONTEXT_CHARS = 4000
MAX_REVIEW_CONTEXT_CHARS = 24000
Expand Down Expand Up @@ -542,6 +556,10 @@ def require_distinct_pr_author(pr: dict[str, Any], actor: str) -> str:
def fetch_diff(repo: str, number: int) -> tuple[str, bool]:
"""Fetch the PR diff and truncate it to the bounded LLM prompt size."""
diff = run(["gh", "api", f"repos/{repo}/pulls/{number}", "-H", "Accept: application/vnd.github.v3.diff"])
if complete_auto_input():
if len(diff.encode("utf-8")) > MAX_AUTO_REVIEW_REQUEST_BYTES:
raise RuntimeError("Noema complete review input exceeds personal auto budget")
return diff, False
truncated = len(diff) > MAX_DIFF_CHARS
if truncated:
marker = "[overlong changed line content omitted]"
Expand Down Expand Up @@ -1625,6 +1643,8 @@ def call_llm(
"Noema LLM review unavailable: NOEMA_LLM_API_URL or NOEMA_LLM_API_KEY is not configured."
)
reject_private_llm_url(api_url)
if complete_auto_input() and truncated:
raise RuntimeError("Noema complete review input requires an untruncated diff")

allowed_locations = [
{"path": path, "line": line, "side": side}
Expand All @@ -1633,7 +1653,10 @@ def call_llm(
location_example = allowed_locations[0] if allowed_locations else {
"path": "path", "line": 0, "side": "RIGHT"
}
allowed_locations_json = _bounded_allowed_locations_json(allowed_locations)
allowed_locations_json = (
json.dumps({"locations": allowed_locations, "truncated": False}, separators=(",", ":"))
if complete_auto_input() else _bounded_allowed_locations_json(allowed_locations)
)
prompt = {
"role": "user",
"content": "\n".join(
Expand Down Expand Up @@ -1668,9 +1691,12 @@ def call_llm(
prompt,
],
}
payload_bytes = json.dumps(payload).encode("utf-8")
if complete_auto_input() and len(payload_bytes) > MAX_AUTO_REVIEW_REQUEST_BYTES:
raise RuntimeError("Noema complete review input exceeds personal auto budget")
request = urllib.request.Request(
api_url,
data=json.dumps(payload).encode("utf-8"),
data=payload_bytes,
headers={
"authorization": f"Bearer {api_key}",
"content-type": "application/json",
Expand Down
16 changes: 16 additions & 0 deletions tests/test_agent_review_runtime_quality_consolidation.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ def test_ghas_runtime_changes_start_the_quality_runner(changed_path: str) -> Non
@pytest.mark.parametrize(
("changed_path", "expected_suites"),
(
("tests/test_noema_complete_auto_input.py", {"review_repair"}),
("scripts/ci/noema_review_gate.py", {"noema", "review_repair"}),
("scripts/ci/codeql_ghas_configuration_identity.py", {"ghas"}),
("tests/test_codeql_ghas_configuration_identity.py", {"ghas"}),
("tests/test_codeql_ghas_analyses_pagination.py", {"ghas"}),
Expand Down Expand Up @@ -385,3 +387,17 @@ def test_exact_artifact_suite_preserves_version_and_quality_contracts() -> None:
assert "outputs.exact_artifact == 'true'" in workflow
assert "--include=scripts/ci/verify_exact_artifact_sbom_handoff.py" in workflow
assert "interrogate --fail-under=100" in workflow


def test_complete_serializer_enrollment():
workflow = _workflow_text()
path = "tests/test_noema_complete_auto_input.py"
trigger = workflow.split("on:\n", 1)[1].split("\nconcurrency:\n", 1)[0]
assert f' - "{path}"' in trigger
assert workflow.count(path) == 4
step = next(part for part in workflow.split(' - name: ')
if 'python -m pytest -q' in part and path in part)
pytest_args = step.split('python -m pytest -q', 1)[1].split('python -m interrogate', 1)[0]
compile_args = step.split('python -m compileall -q', 1)[1]
assert pytest_args.count(path) == 1
assert compile_args.count(path) == 1
70 changes: 70 additions & 0 deletions tests/test_noema_complete_auto_input.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""Complete source admission through the real Noema serializer (no network)."""
import json
from unittest.mock import patch
import pytest
from scripts.ci import noema_review_gate as gate


def test_real_serializer_preserves_all_locations(monkeypatch):
monkeypatch.setenv('NOEMA_LLM_MODEL', 'auto')
monkeypatch.setenv('NOEMA_LLM_API_URL', 'https://litellm.poinnetworks.net/v1/chat/completions')
monkeypatch.setenv('NOEMA_LLM_API_KEY', 'inert-test-value')
monkeypatch.setattr(gate, 'reject_private_llm_url', lambda _: None)
diff = 'diff --git a/a.py b/a.py\n--- a/a.py\n+++ b/a.py\n@@ -0,0 +1,1000 @@\n' + '+line\n'*1000
class Captured(BaseException):
pass
requests = []
def capture(request):
requests.append(request.data)
raise Captured()
with patch.object(gate.urllib.request, 'build_opener') as opener:
opener.return_value.open.side_effect = capture
with pytest.raises(Captured):
gate.call_llm('o/r', 1, {}, diff, False, 'a'*40)
payload = json.loads(requests[0])
prompt = payload['messages'][1]['content']
locations = json.loads(next(line.split(': ', 1)[1] for line in prompt.splitlines()
if line.startswith('Allowed changed-side locations: ')))
assert not locations['truncated']
assert len(locations['locations']) == 1000
assert prompt.endswith(diff)
assert len(requests[0]) <= gate.MAX_AUTO_REVIEW_REQUEST_BYTES


def test_auto_fetch_preserves_complete_diff(monkeypatch):
monkeypatch.setenv('NOEMA_LLM_MODEL', 'auto')
monkeypatch.setenv('NOEMA_LLM_API_URL', 'https://litellm.poinnetworks.net/v1/chat/completions')
diff = 'diff --git a/a.py b/a.py\n--- a/a.py\n+++ b/a.py\n@@ -0,0 +1,2 @@\n+' + 'a'*61000 + '\n+final_source_line\n'
monkeypatch.setattr(gate, 'run', lambda _: diff)
assert gate.fetch_diff('o/r', 1) == (diff, False)


def test_real_serializer_rejects_oversized_auto_before_network(monkeypatch):
monkeypatch.setenv('NOEMA_LLM_MODEL', 'auto')
monkeypatch.setenv('NOEMA_LLM_API_URL', 'https://litellm.poinnetworks.net/v1/chat/completions')
monkeypatch.setenv('NOEMA_LLM_API_KEY', 'inert-test-value')
monkeypatch.setattr(gate, 'reject_private_llm_url', lambda _: None)
with patch.object(gate.urllib.request, 'build_opener') as opener:
with pytest.raises(RuntimeError, match='complete review input exceeds'):
gate.call_llm('o/r', 1, {'headRefOid':'a'*40}, '+'+'x'*500000, False, 'a'*40)
opener.assert_not_called()


@pytest.mark.parametrize('model,url', [('auto','https://example.com/v1/chat/completions'), ('orchestrator/auto','https://litellm.poinnetworks.net/v1/chat/completions')])
def test_other_routes_keep_existing_bound(monkeypatch, model, url):
monkeypatch.setenv('NOEMA_LLM_MODEL', model)
monkeypatch.setenv('NOEMA_LLM_API_URL', url)
monkeypatch.setattr(gate, 'run', lambda _: 'x'*61000)
text, truncated = gate.fetch_diff('o/r', 1)
assert truncated and len(text) <= gate.MAX_DIFF_CHARS


def test_auto_rejects_partial_input(monkeypatch):
monkeypatch.setenv('NOEMA_LLM_MODEL', 'auto')
monkeypatch.setenv('NOEMA_LLM_API_URL', 'https://litellm.poinnetworks.net/v1/chat/completions')
monkeypatch.setenv('NOEMA_LLM_API_KEY', 'inert-test-value')
monkeypatch.setattr(gate, 'reject_private_llm_url', lambda _: None)
with patch.object(gate.urllib.request, 'build_opener') as opener:
with pytest.raises(RuntimeError, match='untruncated'):
gate.call_llm('o/r', 1, {}, 'partial', True, 'a'*40)
opener.assert_not_called()
Loading