open-swe/agent/tools/list_repos.py

60 lines
2.4 KiB
Python
Raw Normal View History

feat: stop auto-cloning and let agent manage repo setup [closes OPE-21] (#1159) * feat: authenticate git operations via sandbox proxy instead of credential files * feat: authenticate git operations via sandbox proxy instead of credential files * feat: authenticate git operations via sandbox proxy instead of credential files * removing logger.info * formatting and linting * fix: resolve lint errors in server.py (imports, unused vars, undefined names) * feat: use opaque proxy headers for GitHub auth in sandbox * linting formatting and test changes * linting * Delete .claude directory * Delete tests/evals directory * fix: address PR review — guard missing tokens, quote shell paths, add proxy auth tests * fix: restore authorship, branch_name support, and installation token for PR creation * linitng * fix: move installation token fetch before commit, clean up dead proxy validation code * feat: stop auto-cloning and let agent manage repo setup [closes OPE-21] * feat: stop auto-cloning and let agent manage repo setup [closes OPE-21] * fix: address review feedback — restore agents_md, add git user config, lint fixes * fix: drop github_token arg from sandbox creation, use generic create_sandbox factory with langsmith-only proxy config * fix: use _get_langsmith_api_key() for prod key fallback, warn when API key missing for proxy config * linting * linting * feat: add installation token auth to list_repos GitHub API call * agents.md update * linting * fix: address PR review feedback — shell precedence bug in prompt, remove dead code * linting * Apply suggestion from @bracesproul Co-authored-by: Brace Sproul <braceasproul@gmail.com> * Apply suggestion from @bracesproul Co-authored-by: Brace Sproul <braceasproul@gmail.com> * fix: address PR review feedback — restore {working_dir} in prompt, remove clone code block * fix:Extract check_or_recreate_sandbox utility from inline sandbox health check * fix: address PR review feedback — async list_repos, restore template name, fix prompt colon * fix: resolve merge conflicts with main, adopt deepagents v0.5.0a4 LangSmithSandbox * linting * yogesh/ope-21-stop-auto-cloning * Update agent/tools/list_repos.py Co-authored-by: Brace Sproul <braceasproul@gmail.com> * Update agent/prompt.py Co-authored-by: Brace Sproul <braceasproul@gmail.com> * feat: address PR review — list_repos uses GitHub API only, PR trigger includes org/repo * linting * feat: address PR review feedback — list_repos pagination, simpler return, sandbox health check * feat: support listing repos for personal user accounts via is_organization flag --------- Co-authored-by: Brace Sproul <braceasproul@gmail.com>
2026-04-10 17:04:55 -07:00
import logging
from typing import Any
import httpx
from ..utils.github_app import get_github_app_installation_token
logger = logging.getLogger(__name__)
async def list_repos(
organization_name: str,
is_organization: bool = True,
page: int = 1,
per_page: int = 100,
sort: str = "updated",
name_filter: str | None = None,
) -> dict[str, Any]:
"""List GitHub repositories for an organization or user via the GitHub API.
Uses /orgs/{name}/repos for organizations and /users/{name}/repos for
personal user accounts, based on the is_organization flag.
Args:
organization_name: The GitHub organization or username to list repos for.
is_organization: If True, uses the /orgs/ endpoint. If False, uses the
/users/ endpoint for personal accounts. Default: True.
page: Page number to fetch (default: 1).
per_page: Number of repos per page, max 100 (default: 100).
sort: Sort field — "updated", "created", "pushed", or "full_name" (default: "updated").
name_filter: Optional substring to filter repo names by (case-insensitive).
If unsure which repo to use, ask the user for confirmation.
"""
try:
headers = {"Accept": "application/vnd.github+json"}
token = await get_github_app_installation_token()
if token:
headers["Authorization"] = f"Bearer {token}"
path_prefix = "orgs" if is_organization else "users"
async with httpx.AsyncClient() as client:
response = await client.get(
f"https://api.github.com/{path_prefix}/{organization_name}/repos",
headers=headers,
params={"per_page": min(per_page, 100), "sort": sort, "page": page},
timeout=10,
)
if response.status_code == 200:
repos: list[str] = [r["name"] for r in response.json()]
if name_filter:
repos = [r for r in repos if name_filter.lower() in r.lower()]
has_next = 'rel="next"' in response.headers.get("link", "")
result: dict[str, Any] = {"repos": repos, "page": page, "has_next_page": has_next}
return result
return {"error": f"GitHub API returned status {response.status_code}"}
except Exception:
logger.warning("Failed to fetch repos for %s", organization_name)
return {"error": f"Failed to fetch repos for {organization_name}"}