"""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")