mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 18:33:15 +00:00
* feat: report Open SWE Review as a PR check run Auto-review dispatch now creates an in-progress 'Open SWE Review' check run on the PR head SHA; publish_review completes it (neutral with findings, success when clean). An after-agent hook fails the check if the run dies before publishing. Requires the GitHub App's Checks: Read & write permission; all calls are best-effort so a missing permission never breaks reviews. * fix: address review feedback on check-run settling Keep review_check_run_id when the completion PATCH fails so a later publish or the after-agent hook can retry instead of hanging the check; count out-of-diff findings toward the check conclusion. * fix: retry failed check completion with the real publish conclusion A transient PATCH failure after a successful publish previously left the check id for the after-agent hook, which settled it as 'failure'. Persist the intended result as review_check_pending_result and have the hook prefer it over the generic failure fallback. --------- Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
84 lines
3.2 KiB
Python
84 lines
3.2 KiB
Python
"""After-agent middleware that closes a still-open review check run.
|
|
|
|
``publish_review`` normally completes the ``Open SWE Review`` check run and
|
|
clears ``review_check_run_id`` from reviewer thread metadata. If the run ends
|
|
without ever publishing (crash, model-call limit, sandbox failure), the check
|
|
would hang "in progress" on the PR forever. This hook closes it as a failure
|
|
so the PR's checks section reflects reality.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Any
|
|
|
|
from langchain.agents.middleware import AgentState, after_agent
|
|
from langgraph.config import get_config
|
|
from langgraph.runtime import Runtime
|
|
|
|
from ..reviewer_findings import get_thread_metadata
|
|
from ..reviewer_publish import settle_review_check_run
|
|
from ..utils.github_token import get_github_token
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@after_agent
|
|
async def settle_review_check_on_exit(
|
|
state: AgentState,
|
|
runtime: Runtime,
|
|
) -> dict[str, Any] | None:
|
|
"""Fail the tracked review check run if the run ended without publishing."""
|
|
config = get_config()
|
|
configurable = config.get("configurable", {})
|
|
if not isinstance(configurable, dict):
|
|
return None
|
|
thread_id = configurable.get("thread_id")
|
|
repo_config = configurable.get("repo")
|
|
if not isinstance(thread_id, str) or not thread_id or not isinstance(repo_config, dict):
|
|
return None
|
|
owner = repo_config.get("owner")
|
|
repo = repo_config.get("name")
|
|
if not isinstance(owner, str) or not owner or not isinstance(repo, str) or not repo:
|
|
return None
|
|
|
|
try:
|
|
metadata = await get_thread_metadata(thread_id)
|
|
if not isinstance(metadata.get("review_check_run_id"), int):
|
|
return None
|
|
token = get_github_token()
|
|
if not token:
|
|
logger.warning("No GitHub token to settle stale review check on thread %s", thread_id)
|
|
return None
|
|
# A pending result means publish_review DID finish but its completion
|
|
# PATCH failed transiently — retry with the real conclusion instead of
|
|
# misreporting a published review as failed.
|
|
pending = metadata.get("review_check_pending_result")
|
|
if isinstance(pending, dict) and pending.get("conclusion") in {
|
|
"success",
|
|
"neutral",
|
|
"failure",
|
|
}:
|
|
conclusion = pending["conclusion"]
|
|
title = str(pending.get("title") or "Review completed")
|
|
summary = str(pending.get("summary") or "")
|
|
else:
|
|
conclusion = "failure"
|
|
title = "Review did not complete"
|
|
summary = (
|
|
"The Open SWE review run ended without publishing a review. "
|
|
"Re-trigger the review by pushing a commit or re-requesting it."
|
|
)
|
|
await settle_review_check_run(
|
|
thread_id=thread_id,
|
|
owner=owner,
|
|
repo=repo,
|
|
token=token,
|
|
conclusion=conclusion,
|
|
title=title,
|
|
summary=summary,
|
|
)
|
|
logger.info("Settled stale review check run for thread %s", thread_id)
|
|
except Exception:
|
|
logger.exception("Failed to settle stale review check run for thread %s", thread_id)
|
|
return None
|