open-swe/agent/ci_monitor.py
Johannes du Plessis 7397ff93ba
feat: CI auto-fix and PR babysitting for agent PRs (#1530)
* feat: CI auto-fix and PR babysitting for agent PRs

Watch CI failures and review feedback on PRs Open SWE opened, then dispatch
confidence-gated fix runs on the originating agent thread. Adds CI webhook
ingestion (check_run/check_suite/workflow_run/status), a per-PR @open-swe
autofix on|off toggle, auto-response to review comments, and a polling
ci_monitor graph that also flags merge conflicts. Gated by the existing
autofix_mode/trigger_mode settings, the enabled-repos opt-in, base-branch and
human-commit skip rules, dedupe, and a per-PR attempt cap.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

* fix: address review feedback on CI auto-fix

- Security: gate the no-mention review-feedback path on author trust —
  require a trusted author_association (OWNER/MEMBER/COLLABORATOR) plus a
  GitHub write/maintain/admin permission check before dispatching a
  write-capable agent run, preventing privilege escalation from
  read/triage/outside reviewers.
- Auth: reuse the originating PR thread's source + login/email when
  dispatching fix runs so the GitHub-token resolver authenticates them in
  non-bot-token deployments (bespoke github_ci source failed to resolve).
- Docs: document the Commit statuses: Read-only permission required for the
  Status webhook event.

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>

---------

Co-authored-by: open-swe[bot] <open-swe@users.noreply.github.com>
2026-06-15 13:53:50 -07:00

35 lines
1.1 KiB
Python

"""LangGraph entrypoint that polls open agent PRs for CI failures / conflicts.
A fallback for deployments where CI webhooks (``check_run`` / ``workflow_run``)
aren't reliably delivered, and the only path that can react to base-branch
merge conflicts (GitHub emits no webhook for those). Register it on a cron to
sweep periodically; each tick calls :func:`agent.ci_autofix.sweep_open_prs`.
"""
from __future__ import annotations
import logging
from typing import Any, TypedDict
from langgraph.graph import END, START, StateGraph
from langgraph.graph.state import RunnableConfig
from .ci_autofix import sweep_open_prs
logger = logging.getLogger(__name__)
class CIMonitorState(TypedDict, total=False):
result: dict[str, Any]
async def _sweep(_state: CIMonitorState, _config: RunnableConfig) -> dict[str, Any]:
return {"result": await sweep_open_prs()}
def get_ci_monitor(config: RunnableConfig | None = None):
builder = StateGraph(CIMonitorState)
builder.add_node("sweep", _sweep)
builder.add_edge(START, "sweep")
builder.add_edge("sweep", END)
return builder.compile().with_config(config or {})