open-swe/agent/utils/agents_md.py

74 lines
2.1 KiB
Python
Raw Normal View History

"""Fetch ``AGENTS.md`` from a GitHub repo so it can be inlined into prompts.
Used by the reviewer to deterministically load repo conventions into context
without the model having to clone the repo and read the file itself.
"""
from __future__ import annotations
import logging
import httpx
logger = logging.getLogger(__name__)
# Cap the inlined content. AGENTS.md is meant to be a short conventions doc;
# anything larger is probably accidental and would bloat every reviewer prompt.
_MAX_AGENTS_MD_BYTES = 64 * 1024
async def fetch_agents_md(
owner: str,
repo: str,
ref: str,
*,
token: str | None,
timeout: float = 10.0,
) -> str | None:
"""Fetch ``AGENTS.md`` at ``ref`` from ``owner/repo``.
Returns the raw file contents, or ``None`` if the file is missing, the
request fails, or the file exceeds the size cap.
"""
if not owner or not repo or not ref:
return None
url = f"https://api.github.com/repos/{owner}/{repo}/contents/AGENTS.md"
headers = {
"Accept": "application/vnd.github.raw",
"X-GitHub-Api-Version": "2022-11-28",
}
if token:
headers["Authorization"] = f"Bearer {token}"
try:
async with httpx.AsyncClient(timeout=timeout) as client:
response = await client.get(url, headers=headers, params={"ref": ref})
except httpx.HTTPError:
logger.exception("Failed to fetch AGENTS.md from %s/%s@%s", owner, repo, ref)
return None
if response.status_code == 404:
return None
if response.status_code != 200:
logger.warning(
"Unexpected status %s fetching AGENTS.md from %s/%s@%s",
response.status_code,
owner,
repo,
ref,
)
return None
content = response.text
if len(content.encode("utf-8")) > _MAX_AGENTS_MD_BYTES:
logger.info(
"AGENTS.md in %s/%s@%s exceeds %d bytes; skipping inline",
owner,
repo,
ref,
_MAX_AGENTS_MD_BYTES,
)
return None
return content