Route agents to owning application files
Some checks failed
CI / test (push) Has been cancelled

This commit is contained in:
2026-08-28 13:39:37 +02:00
parent 75894f8b52
commit 0f2f131034
6 changed files with 57 additions and 8 deletions

View File

@@ -13,11 +13,11 @@ class AiderAgent:
def __init__(self, settings: Settings) -> None:
self.settings = settings
def run(self, workspace: Path, task: str) -> str:
def run(self, workspace: Path, task: str, files: tuple[str, ...] = ()) -> str:
task_file = workspace / ".git" / "failure-task.txt"
task_file.write_text(task)
task_file.chmod(0o600)
command = self.command(task_file)
command = self.command(task_file, files)
coder = pwd.getpwnam("coder")
git_config = Path(coder.pw_dir) / ".gitconfig"
git_config.write_text(
@@ -66,8 +66,8 @@ class AiderAgent:
raise RuntimeError(f"Aider failed ({result.returncode}): {result.stderr[-4000:]}")
return result.stdout[-12_000:]
def command(self, task_file: Path) -> list[str]:
return [
def command(self, task_file: Path, files: tuple[str, ...] = ()) -> list[str]:
command = [
self.settings.agent_command,
"--model",
self.settings.agent_model,
@@ -88,3 +88,7 @@ class AiderAgent:
"--timeout",
"180",
]
for filename in files:
if (task_file.parent.parent / filename).is_file():
command.extend(["--file", filename])
return command

View File

@@ -71,7 +71,9 @@ def evaluate_changes(
def evaluate_report_scope(report: FailureReport, summary: ChangeSummary) -> PolicyResult:
expected = f"{report.user_feedback or ''}\n{report.expected_behavior or ''}".lower()
requires_cross_database_orchestration = "cockpit_config" in expected and "fk_" in expected
requires_cross_database_orchestration = (
"cockpit_config" in expected and ("fk_" in expected or "erp" in expected)
)
has_application_change = any(filename.startswith("app/") for filename in summary.files)
errors = []
if requires_cross_database_orchestration and not has_application_change:

View File

@@ -59,6 +59,23 @@ def redact(value: str | None) -> str:
return result[:12_000]
def repair_files(report: FailureReport) -> tuple[str, ...]:
expected = f"{report.user_feedback or ''}\n{report.expected_behavior or ''}".lower()
if "cockpit_config" in expected and ("fk_" in expected or "erp" in expected):
return (
"app/Http/Controllers/ChatController.php",
"app/Services/TenantDatabaseService.php",
"tests/Unit/ChatControllerSourceResolutionTest.php",
)
if '__LAI_' in (report.response or ''):
return (
"app/Services/AIService.php",
"app/Http/Controllers/ChatController.php",
"tests/Feature/AIPrivacyBoundaryTest.php",
)
return ()
def build_task(report: FailureReport) -> str:
prompt = redact(report.prompt)
feedback = redact(report.user_feedback)

View File

@@ -18,7 +18,7 @@ from .git import ChangeSummary, GitWorkspace
from .gitea import GiteaClient
from .models import FailureReport
from .policy import evaluate_changes, evaluate_report_scope
from .prompt import build_retry_task, build_task
from .prompt import build_retry_task, build_task, repair_files
LOG = logging.getLogger(__name__)
@@ -57,6 +57,9 @@ class AutomationWorker:
workspace.prepare()
LOG.info("Report %s branch=%s workspace ready", report.id, workspace.branch)
task = build_task(report)
files = repair_files(report)
if files:
LOG.info("Report %s routed editable files=%s", report.id, ",".join(files))
metadata["agent_output"] = []
valid_checkpoint: str | None = None
for attempt in range(1, self.settings.max_agent_attempts + 1):
@@ -67,7 +70,7 @@ class AutomationWorker:
self.settings.max_agent_attempts,
)
with self._progress(report.id, f"agent attempt {attempt}"):
metadata["agent_output"].append(self.agent.run(workspace.path, task))
metadata["agent_output"].append(self.agent.run(workspace.path, task, files))
summary = workspace.summary()
metadata["changes"] = asdict(summary)
LOG.info(
@@ -94,6 +97,8 @@ class AutomationWorker:
attempt,
"; ".join(policy.errors),
)
if not scope_policy.allowed:
workspace.restore_checkpoint(None)
task = build_retry_task(
report,
RuntimeError(