open-swe/agent/tools/list_repos.py
Aran Yogesh 2039fe6660
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

59 lines
2.4 KiB
Python

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}"}