Spaces:
Sleeping
Sleeping
| """Git tools for auto-swe-agent. All commands run inside the Docker sandbox.""" | |
| import re | |
| from typing import List, Optional | |
| from langchain_core.tools import tool | |
| def _run_in_sandbox(command: str, workspace_dir: str = "./") -> tuple[int, str]: | |
| """Run a shell command in the Docker sandbox, return (exit_code, output).""" | |
| # Import here to avoid circular imports with agent.py | |
| from agent import get_sandbox | |
| container = get_sandbox(workspace_dir) | |
| result = container.exec_run( | |
| ["bash", "-c", command], workdir="/workspace", demux=False | |
| ) | |
| output = (result.output or b"").decode().strip() | |
| return result.exit_code, output | |
| def create_branch(branch_name: str, workspace_dir: str = "./") -> str: | |
| """Create and checkout a new git branch in the Docker sandbox. | |
| Branch name must be lowercase with hyphens only (no spaces or special chars). | |
| """ | |
| # Validate branch name | |
| if not re.match(r"^[a-z0-9/][a-z0-9\-/]*$", branch_name): | |
| return f"Error: invalid branch name '{branch_name}'. Use lowercase letters, numbers, hyphens, and forward slashes only." | |
| exit_code, output = _run_in_sandbox(f"git checkout -b {branch_name}", workspace_dir) | |
| if exit_code != 0: | |
| return f"Error creating branch: {output}" | |
| return f"Created and checked out branch: {branch_name}" | |
| def commit_changes( | |
| message: str, workspace_dir: str = "./", files: Optional[List[str]] = None | |
| ) -> str: | |
| """Stage and commit changes in the Docker sandbox. | |
| If files is provided, only those files are staged; otherwise all changes are staged. | |
| Commit message is auto-prefixed with 'auto-swe: ' if not already present. | |
| """ | |
| if not message.startswith("auto-swe:"): | |
| message = f"auto-swe: {message}" | |
| # Configure git identity inside container (required for commits) | |
| _run_in_sandbox( | |
| 'git config user.email "agent@auto-swe-agent" && git config user.name "auto-swe-agent"', | |
| workspace_dir, | |
| ) | |
| if files: | |
| file_list = " ".join(f'"{f}"' for f in files) | |
| add_cmd = f"git add {file_list}" | |
| else: | |
| add_cmd = "git add -A" | |
| exit_code, output = _run_in_sandbox(add_cmd, workspace_dir) | |
| if exit_code != 0: | |
| return f"Error staging files: {output}" | |
| exit_code, output = _run_in_sandbox(f'git commit -m "{message}"', workspace_dir) | |
| if exit_code != 0: | |
| return f"Error committing: {output}" | |
| # Extract commit hash from output | |
| commit_hash = "" | |
| for line in output.splitlines(): | |
| if line.startswith("["): | |
| # e.g. "[main abc1234] auto-swe: fix something" | |
| parts = line.split() | |
| if len(parts) >= 2: | |
| commit_hash = parts[1].rstrip("]") | |
| break | |
| return f"Committed: {message}\nHash: {commit_hash}\n{output}" | |
| def generate_pr_description(workspace_dir: str = "./") -> str: | |
| """Generate a pull request description based on the latest git diff. | |
| Uses git diff HEAD~1 if commits exist, otherwise git diff for staged changes. | |
| """ | |
| # Try diff against previous commit first | |
| exit_code, diff = _run_in_sandbox( | |
| "git diff HEAD~1 --stat 2>/dev/null || git diff --stat", workspace_dir | |
| ) | |
| _, full_diff = _run_in_sandbox( | |
| "git diff HEAD~1 2>/dev/null || git diff", workspace_dir | |
| ) | |
| # Truncate diff for context window | |
| if len(full_diff) > 3000: | |
| full_diff = full_diff[:3000] + "\n... [diff truncated]" | |
| # Parse changed files from stat output | |
| changed_files = [] | |
| for line in diff.splitlines(): | |
| line = line.strip() | |
| if "|" in line and not line.startswith("---"): | |
| fname = line.split("|")[0].strip() | |
| if fname: | |
| changed_files.append(fname) | |
| files_section = ( | |
| "\n".join(f"- `{f}`" for f in changed_files) | |
| if changed_files | |
| else "- (see diff)" | |
| ) | |
| pr_description = f"""## Changes | |
| {files_section} | |
| ## Testing | |
| - pytest passed ✓ | |
| ## Diff Summary | |
| ``` | |
| {full_diff} | |
| ``` | |
| --- | |
| *Generated by auto-swe-agent*""" | |
| return pr_description | |