This commit is contained in:
@@ -17,6 +17,7 @@ services:
|
|||||||
GITEA_REPOSITORY: ${GITEA_REPOSITORY:-lai}
|
GITEA_REPOSITORY: ${GITEA_REPOSITORY:-lai}
|
||||||
GITEA_USERNAME: ${GITEA_USERNAME:-automation-bot}
|
GITEA_USERNAME: ${GITEA_USERNAME:-automation-bot}
|
||||||
GITEA_TOKEN: ${GITEA_TOKEN:-}
|
GITEA_TOKEN: ${GITEA_TOKEN:-}
|
||||||
|
AGENT_COMMAND: ${AGENT_COMMAND:-aider}
|
||||||
AGENT_MODEL: ${AGENT_MODEL:-mistral/mistral-medium-latest}
|
AGENT_MODEL: ${AGENT_MODEL:-mistral/mistral-medium-latest}
|
||||||
MISTRAL_API_KEY: ${MISTRAL_API_KEY:-}
|
MISTRAL_API_KEY: ${MISTRAL_API_KEY:-}
|
||||||
POLL_SECONDS: ${POLL_SECONDS:-60}
|
POLL_SECONDS: ${POLL_SECONDS:-60}
|
||||||
|
|||||||
@@ -16,17 +16,7 @@ class AiderAgent:
|
|||||||
task_file = workspace / ".git" / "failure-task.txt"
|
task_file = workspace / ".git" / "failure-task.txt"
|
||||||
task_file.write_text(task)
|
task_file.write_text(task)
|
||||||
task_file.chmod(0o600)
|
task_file.chmod(0o600)
|
||||||
command = [
|
command = self.command(task_file)
|
||||||
self.settings.agent_command,
|
|
||||||
"--model",
|
|
||||||
self.settings.agent_model,
|
|
||||||
"--message-file",
|
|
||||||
str(task_file),
|
|
||||||
"--yes",
|
|
||||||
"--no-auto-commits",
|
|
||||||
"--no-dirty-commits",
|
|
||||||
"--no-stream",
|
|
||||||
]
|
|
||||||
coder = pwd.getpwnam("coder")
|
coder = pwd.getpwnam("coder")
|
||||||
os.chown(task_file, coder.pw_uid, coder.pw_gid)
|
os.chown(task_file, coder.pw_uid, coder.pw_gid)
|
||||||
for path in workspace.rglob("*"):
|
for path in workspace.rglob("*"):
|
||||||
@@ -47,16 +37,39 @@ class AiderAgent:
|
|||||||
os.setgid(coder.pw_gid)
|
os.setgid(coder.pw_gid)
|
||||||
os.setuid(coder.pw_uid)
|
os.setuid(coder.pw_uid)
|
||||||
|
|
||||||
result = subprocess.run(
|
try:
|
||||||
command,
|
result = subprocess.run(
|
||||||
cwd=workspace,
|
command,
|
||||||
env=environment,
|
cwd=workspace,
|
||||||
text=True,
|
env=environment,
|
||||||
capture_output=True,
|
text=True,
|
||||||
check=False,
|
capture_output=True,
|
||||||
preexec_fn=drop_privileges,
|
check=False,
|
||||||
timeout=3600,
|
preexec_fn=drop_privileges,
|
||||||
)
|
timeout=900,
|
||||||
|
)
|
||||||
|
finally:
|
||||||
|
os.chown(workspace, 0, coder.pw_gid, follow_symlinks=False)
|
||||||
|
workspace.chmod(0o775)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
raise RuntimeError(f"Aider failed ({result.returncode}): {result.stderr[-4000:]}")
|
raise RuntimeError(f"Aider failed ({result.returncode}): {result.stderr[-4000:]}")
|
||||||
return result.stdout[-12_000:]
|
return result.stdout[-12_000:]
|
||||||
|
|
||||||
|
def command(self, task_file: Path) -> list[str]:
|
||||||
|
return [
|
||||||
|
self.settings.agent_command,
|
||||||
|
"--model",
|
||||||
|
self.settings.agent_model,
|
||||||
|
"--message-file",
|
||||||
|
str(task_file),
|
||||||
|
"--yes",
|
||||||
|
"--no-auto-commits",
|
||||||
|
"--no-dirty-commits",
|
||||||
|
"--no-stream",
|
||||||
|
"--no-gitignore",
|
||||||
|
"--chat-history-file",
|
||||||
|
"/dev/null",
|
||||||
|
"--input-history-file",
|
||||||
|
"/dev/null",
|
||||||
|
"--no-analytics",
|
||||||
|
]
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ class GitWorkspace:
|
|||||||
shutil.rmtree(self.path, ignore_errors=True)
|
shutil.rmtree(self.path, ignore_errors=True)
|
||||||
self.path.parent.mkdir(parents=True, exist_ok=True)
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
self._git("clone", "--branch", self.settings.source_branch, "--single-branch", self.settings.source_repository, str(self.path), cwd=self.path.parent)
|
self._git("clone", "--branch", self.settings.source_branch, "--single-branch", self.settings.source_repository, str(self.path), cwd=self.path.parent)
|
||||||
|
self._git("config", "user.name", "LAI Automation")
|
||||||
|
self._git("config", "user.email", "automation@localhost")
|
||||||
self._git("checkout", "-b", self.branch)
|
self._git("checkout", "-b", self.branch)
|
||||||
|
|
||||||
def run(
|
def run(
|
||||||
|
|||||||
14
tests/test_agent.py
Normal file
14
tests/test_agent.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from test_config import settings
|
||||||
|
|
||||||
|
from lai_automation.agent import AiderAgent
|
||||||
|
|
||||||
|
|
||||||
|
def test_aider_command_cannot_mutate_git_configuration_or_send_analytics() -> None:
|
||||||
|
command = AiderAgent(settings()).command(Path("/repo/.git/task.txt"))
|
||||||
|
|
||||||
|
assert "--no-gitignore" in command
|
||||||
|
assert "--no-analytics" in command
|
||||||
|
assert "--no-auto-commits" in command
|
||||||
|
assert command.count("/dev/null") == 2
|
||||||
Reference in New Issue
Block a user