Spaces:
Running
Running
| """Patch: agent_loop.py task detection + auto-approve for free models.""" | |
| import os | |
| import ast | |
| AGENT_LOOP = "/app/agent/core/agent_loop.py" | |
| AGENT_FILE = "/app/backend/routes/agent.py" | |
| SESSION_FILE = "/app/agent/core/session.py" | |
| # ===== PATCH 1: agent_loop.py - detect model stopped mid-task ===== | |
| with open(AGENT_LOOP) as f: | |
| c = f.read() | |
| # Add helper function before class Handlers | |
| if "_unfinished_plan" not in c: | |
| fn = ( | |
| "\n\ndef _unfinished_plan(s):\n" | |
| " p = getattr(s, 'current_plan', None) or []\n" | |
| " return [it for it in p if it.get('status') in ('pending', 'in_progress')]\n\n" | |
| ) | |
| c = c.replace("class Handlers:", fn + "class Handlers:") | |
| print("OK: Added _unfinished_plan()") | |
| # Add detection: if model produced no tool calls but content still exists, | |
| # and plan items are still pending/in_progress, send session_update event | |
| if "ac_plan" not in c: | |
| check = ( | |
| "\n # Auto-continue: detect model stopped mid-task\n" | |
| " if not llm_result.tool_calls_acc and llm_result.content:\n" | |
| " unfinished = _unfinished_plan(session)\n" | |
| " if unfinished:\n" | |
| " await session.send_event(Event(event_type='session_update', data={\n" | |
| " 'ac_plan': unfinished,\n" | |
| " }))\n" | |
| ) | |
| c = c.replace(" # -- End of turn --", check + " # -- End of turn --") | |
| print("OK: Added mid-task detection") | |
| try: | |
| ast.parse(c) | |
| with open(AGENT_LOOP, "w") as f: | |
| f.write(c) | |
| print("OK: agent_loop.py patched") | |
| except SyntaxError as e: | |
| print(f"FAIL: agent_loop.py syntax: {e}") | |
| # ===== PATCH 2: Enable auto_approval for ALL sessions by default ===== | |
| # So free models don't block on user approval | |
| with open(SESSION_FILE) as f: | |
| c = f.read() | |
| if "AUTO_APPROVE" not in c: | |
| # Find where auto_approval is set on the session object | |
| # Patch: when creating a new session, set auto_approval.enabled = True | |
| auto_patch = ( | |
| "\n # === PATCH: Auto-approve for free models ===\n" | |
| " self.auto_approval = {\n" | |
| ' "enabled": True,\n' | |
| ' "cost_cap_usd": None,\n' | |
| ' "estimated_spend_usd": 0.0,\n' | |
| ' "remaining_usd": None,\n' | |
| " }\n" | |
| ) | |
| # Find session init method | |
| init_match = "class Session:" | |
| if init_match in c: | |
| # Insert after the class definition, find __init__ | |
| init_found = "def __init__" | |
| if init_found in c: | |
| # Find first line inside __init__ that's an assignment | |
| init_start = c.find(init_found) | |
| body_start = c.find("\n", init_start) + 1 | |
| body_start = c.find(" ", body_start) # first indented line | |
| c = c[:body_start] + auto_patch + c[body_start:] | |
| print("OK: Added auto_approve default") | |
| try: | |
| ast.parse(c) | |
| with open(SESSION_FILE, "w") as f: | |
| f.write(c) | |
| print("OK: session.py patched") | |
| except SyntaxError as e: | |
| print(f"FAIL: session.py syntax: {e}") | |
| # Don't block on this patch | |
| else: | |
| print("OK: session.py already has auto_approve") | |
| print("DONE: Backend patches applied") |