Add Nexus Agent Runner workflow configuration#15
Conversation
This workflow automates the Nexus Agent Runner with scheduled runs, dependency installation, and self-healing attempts based on test results.
There was a problem hiding this comment.
Pull Request Overview
This PR introduces an automated Nexus Agent Runner workflow that executes on a 30-minute schedule, on pushes to agent branches, and manually. The workflow performs iterative repository scanning, test execution, and implements a multi-stage self-healing mechanism to recover from test failures.
Key changes:
- Adds automated agent runner with scheduled execution every 30 minutes
- Implements three-tier self-healing strategy with diagnostics injection, module reversion, and test isolation
- Creates automatic pull requests when tests pass after healing attempts
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| on: | ||
| schedule: | ||
| - cron: "*/30 * * * *" # every 30 minutes |
There was a problem hiding this comment.
Running this workflow every 30 minutes may consume significant CI/CD resources and GitHub Actions minutes. Consider increasing the interval to hourly or using event-driven triggers based on actual changes to reduce unnecessary runs.
| - cron: "*/30 * * * *" # every 30 minutes | |
| - cron: "0 * * * *" # every hour |
| - name: Install deps | ||
| run: | | ||
| python -m pip install --upgrade pip | ||
| pip install flask ecdsa pytest |
There was a problem hiding this comment.
Dependencies are installed without version pinning, which can lead to unpredictable behavior when package versions change. Consider creating a requirements.txt file with pinned versions or specify versions directly (e.g., flask==2.3.0).
| - name: Install deps | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install flask ecdsa pytest | |
| - name: Create requirements.txt | |
| run: | | |
| echo "flask==2.3.3" > requirements.txt | |
| echo "ecdsa==0.18.0" >> requirements.txt | |
| echo "pytest==7.4.4" >> requirements.txt | |
| - name: Install deps | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt |
| PY | ||
|
|
||
| - name: Run reliability CI (python) | ||
| run: pytest -q || echo "TESTS_FAILED" > .agent/status |
There was a problem hiding this comment.
The pattern of writing 'TESTS_FAILED' to .agent/status is repeated across multiple steps (lines 46, 63, 70, 76). Consider extracting this into a reusable script or shell function to reduce duplication.
| p="simulator/app.py" | ||
| try: | ||
| buf=open(p).read() | ||
| if "LOG_DIAGNOSTICS" not in buf: | ||
| buf = buf.replace("app = Flask(__name__)", "app = Flask(__name__)\nLOG_DIAGNOSTICS=True") | ||
| open(p,"w").write(buf) | ||
| print("Diagnostics flag injected.") | ||
| except FileNotFoundError: | ||
| print("No app.py; skipping.") |
There was a problem hiding this comment.
String replacement for code injection is fragile and will fail if the Flask initialization pattern differs (e.g., with extra whitespace, different quotes, or split across lines). Consider using a more robust approach like AST manipulation or configuration-based diagnostics.
| p="simulator/app.py" | |
| try: | |
| buf=open(p).read() | |
| if "LOG_DIAGNOSTICS" not in buf: | |
| buf = buf.replace("app = Flask(__name__)", "app = Flask(__name__)\nLOG_DIAGNOSTICS=True") | |
| open(p,"w").write(buf) | |
| print("Diagnostics flag injected.") | |
| except FileNotFoundError: | |
| print("No app.py; skipping.") | |
| import ast, os | |
| p = "simulator/app.py" | |
| try: | |
| with open(p, "r") as f: | |
| src = f.read() | |
| if "LOG_DIAGNOSTICS" in src: | |
| print("Diagnostics flag already present.") | |
| else: | |
| tree = ast.parse(src) | |
| class Injector(ast.NodeTransformer): | |
| def __init__(self): | |
| self.injected = False | |
| def visit_Assign(self, node): | |
| # Look for: app = Flask(__name__) | |
| if (isinstance(node.targets[0], ast.Name) and | |
| node.targets[0].id == "app" and | |
| isinstance(node.value, ast.Call) and | |
| getattr(getattr(node.value.func, 'id', None), 'lower', lambda: None)() == "flask" and | |
| len(node.value.args) == 1 and | |
| isinstance(node.value.args[0], ast.Name) and | |
| node.value.args[0].id == "__name__"): | |
| self.injected = True | |
| # Insert LOG_DIAGNOSTICS = True after this node | |
| return [node, ast.parse("LOG_DIAGNOSTICS = True").body[0]] | |
| return node | |
| injector = Injector() | |
| new_tree = injector.visit(tree) | |
| ast.fix_missing_locations(new_tree) | |
| if injector.injected: | |
| new_src = ast.unparse(new_tree) | |
| with open(p, "w") as f: | |
| f.write(new_src) | |
| print("Diagnostics flag injected.") | |
| else: | |
| print("Flask app assignment not found; skipping injection.") | |
| except FileNotFoundError: | |
| print("No app.py; skipping.") |
| - name: Create PR on success | ||
| if: ${{ hashFiles('.agent/status') == '' }} | ||
| run: | | ||
| BR="agent/iteration-$(date +%s)" | ||
| git checkout -b "$BR" | ||
| git add -A | ||
| git commit -m "Agent iteration: CI green, diagnostics added" | ||
| git push origin "$BR" |
There was a problem hiding this comment.
This step will fail because Git operations require authentication and user configuration. The workflow needs to configure git user email/name and use a token with appropriate permissions (e.g., GITHUB_TOKEN) for pushing to the repository.
| run: | | ||
| BR="agent/iteration-$(date +%s)" | ||
| git checkout -b "$BR" | ||
| git add -A |
There was a problem hiding this comment.
Using git add -A stages all changes including potentially sensitive files like logs, credentials, or temporary files. This could inadvertently commit sensitive data. Consider using more specific paths like git add .agent/ or explicitly listing files to commit.
| git add -A | |
| git add .agent/plans .agent/provenance |
| BR="agent/iteration-$(date +%s)" | ||
| git checkout -b "$BR" | ||
| git add -A | ||
| git commit -m "Agent iteration: CI green, diagnostics added" |
There was a problem hiding this comment.
The commit will fail if there are no changes to commit (e.g., when the workflow runs but makes no modifications). Add git diff-index --quiet HEAD || git commit or use git commit --allow-empty to handle this case.
| git commit -m "Agent iteration: CI green, diagnostics added" | |
| git diff-index --quiet HEAD || git commit -m "Agent iteration: CI green, diagnostics added" |
This workflow automates the Nexus Agent Runner with scheduled runs, dependency installation, and self-healing attempts based on test results.