Spaces:
Paused
Paused
Claude Code commited on
Commit ·
7d03e70
1
Parent(s): 5c8e82c
god: implement INVASIVE DIAGNOSTICS Protocol — Break Hypothesis Loop with Actual Crash Logs
Browse files- scripts/conversation-loop.py +67 -1
scripts/conversation-loop.py
CHANGED
|
@@ -1301,7 +1301,14 @@ def gather_context():
|
|
| 1301 |
# 2. Environment variables
|
| 1302 |
ctx["env"] = action_get_env()
|
| 1303 |
|
| 1304 |
-
# 3.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1305 |
cache_key = f"files_{child_state['stage']}"
|
| 1306 |
if cache_key not in _context_cache:
|
| 1307 |
ctx["space_files"] = action_list_files("space")
|
|
@@ -1316,11 +1323,59 @@ def gather_context():
|
|
| 1316 |
return ctx
|
| 1317 |
|
| 1318 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1319 |
def format_context(ctx):
|
| 1320 |
"""Format gathered context into a readable string for the LLM."""
|
| 1321 |
parts = []
|
| 1322 |
parts.append(f"=== HEALTH ===\n{ctx.get('health', 'unknown')}")
|
| 1323 |
parts.append(f"\n=== ENVIRONMENT ===\n{ctx.get('env', 'none')}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1324 |
if ctx.get("space_files"):
|
| 1325 |
parts.append(f"\n=== SPACE FILES ===\n{ctx['space_files'][:2000]}")
|
| 1326 |
if ctx.get("dataset_files"):
|
|
@@ -2257,6 +2312,17 @@ def build_turn_message(speaker, other, ctx):
|
|
| 2257 |
parts.append(f"\n{CHILD_NAME} is {child_state['stage']}. Cooldown active: {int(cooldown_remaining)}s remaining. Discuss plans but DO NOT assign [TASK] until cooldown ends.")
|
| 2258 |
else:
|
| 2259 |
parts.append(f"\n{CHILD_NAME} is {child_state['stage']}. No cooldown. YOU MUST write a [TASK]...[/TASK] to investigate or fix issues. Don't just discuss.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2260 |
# Add recent task reminder during cooldown/building
|
| 2261 |
if recent_task_reminder:
|
| 2262 |
last_completed, last_by, last_at = recent_task_reminder
|
|
|
|
| 1301 |
# 2. Environment variables
|
| 1302 |
ctx["env"] = action_get_env()
|
| 1303 |
|
| 1304 |
+
# 3. INVASIVE DIAGNOSTICS — Fetch actual crash logs when in deadlock states
|
| 1305 |
+
# This breaks the "hypothesize -> check code -> repeat" loop by providing actual runtime errors
|
| 1306 |
+
if child_state["stage"] in ("RUNNING_APP_STARTING", "RUNTIME_ERROR", "BUILD_ERROR"):
|
| 1307 |
+
diagnostic = _fetch_invasive_diagnostics()
|
| 1308 |
+
if diagnostic:
|
| 1309 |
+
ctx["invasive_diagnostics"] = diagnostic
|
| 1310 |
+
|
| 1311 |
+
# 4. File lists (cache, refresh when stage changes)
|
| 1312 |
cache_key = f"files_{child_state['stage']}"
|
| 1313 |
if cache_key not in _context_cache:
|
| 1314 |
ctx["space_files"] = action_list_files("space")
|
|
|
|
| 1323 |
return ctx
|
| 1324 |
|
| 1325 |
|
| 1326 |
+
def _fetch_invasive_diagnostics():
|
| 1327 |
+
"""Fetch actual crash logs and error details from HF API.
|
| 1328 |
+
Bypasses frontend/a2a-proxy to get real runtime errors."""
|
| 1329 |
+
if not child_state["created"]:
|
| 1330 |
+
return None
|
| 1331 |
+
|
| 1332 |
+
diagnostic_parts = []
|
| 1333 |
+
try:
|
| 1334 |
+
# Fetch detailed runtime error from HF Spaces API
|
| 1335 |
+
rresp = requests.get(
|
| 1336 |
+
f"https://huggingface.co/api/spaces/{CHILD_SPACE_ID}/runtime",
|
| 1337 |
+
headers={"Authorization": f"Bearer {HF_TOKEN}"}, timeout=10)
|
| 1338 |
+
if rresp.ok:
|
| 1339 |
+
rdata = rresp.json()
|
| 1340 |
+
error_message = rdata.get("errorMessage", "")
|
| 1341 |
+
if error_message:
|
| 1342 |
+
diagnostic_parts.append(f"=== RUNTIME ERROR MESSAGE ===\n{error_message[:2000]}")
|
| 1343 |
+
|
| 1344 |
+
# Also check stage and runtime info
|
| 1345 |
+
stage = rdata.get("stage", "")
|
| 1346 |
+
if stage:
|
| 1347 |
+
diagnostic_parts.append(f"\n=== RUNTIME STAGE ===\n{stage}")
|
| 1348 |
+
|
| 1349 |
+
# Check if there's runtime info
|
| 1350 |
+
runtime_info = rdata.get("runtime", {})
|
| 1351 |
+
if runtime_info:
|
| 1352 |
+
diagnostic_parts.append(f"\n=== RUNTIME INFO ===\n{str(runtime_info)[:500]}")
|
| 1353 |
+
except Exception as e:
|
| 1354 |
+
diagnostic_parts.append(f"=== DIAGNOSTIC FETCH ERROR ===\n{e}")
|
| 1355 |
+
|
| 1356 |
+
# Try to fetch recent logs from the Space's exposed endpoint (if available)
|
| 1357 |
+
try:
|
| 1358 |
+
lresp = requests.get(f"{CHILD_SPACE_URL}/api/logs", timeout=5)
|
| 1359 |
+
if lresp.ok:
|
| 1360 |
+
logs = lresp.text
|
| 1361 |
+
diagnostic_parts.append(f"\n=== RECENT LOGS (last 1000 chars) ===\n{logs[-1000:]}")
|
| 1362 |
+
except:
|
| 1363 |
+
pass # Endpoint might not exist, that's OK
|
| 1364 |
+
|
| 1365 |
+
return "\n".join(diagnostic_parts) if diagnostic_parts else None
|
| 1366 |
+
|
| 1367 |
+
|
| 1368 |
def format_context(ctx):
|
| 1369 |
"""Format gathered context into a readable string for the LLM."""
|
| 1370 |
parts = []
|
| 1371 |
parts.append(f"=== HEALTH ===\n{ctx.get('health', 'unknown')}")
|
| 1372 |
parts.append(f"\n=== ENVIRONMENT ===\n{ctx.get('env', 'none')}")
|
| 1373 |
+
|
| 1374 |
+
# INVASIVE DIAGNOSTICS — Show crash logs FIRST (before file lists)
|
| 1375 |
+
# This ensures agents see actual runtime errors before hypothesizing
|
| 1376 |
+
if ctx.get("invasive_diagnostics"):
|
| 1377 |
+
parts.append(f"\n=== INVASIVE DIAGNOSTICS (ACTUAL CRASH LOGS) ===\n{ctx['invasive_diagnostics']}")
|
| 1378 |
+
|
| 1379 |
if ctx.get("space_files"):
|
| 1380 |
parts.append(f"\n=== SPACE FILES ===\n{ctx['space_files'][:2000]}")
|
| 1381 |
if ctx.get("dataset_files"):
|
|
|
|
| 2312 |
parts.append(f"\n{CHILD_NAME} is {child_state['stage']}. Cooldown active: {int(cooldown_remaining)}s remaining. Discuss plans but DO NOT assign [TASK] until cooldown ends.")
|
| 2313 |
else:
|
| 2314 |
parts.append(f"\n{CHILD_NAME} is {child_state['stage']}. No cooldown. YOU MUST write a [TASK]...[/TASK] to investigate or fix issues. Don't just discuss.")
|
| 2315 |
+
|
| 2316 |
+
# INVASIVE DIAGNOSTICS PROTOCOL — Break hypothesis loop when in DEADLOCK states
|
| 2317 |
+
# When Cain is stuck starting, agents MUST verify against actual runtime errors
|
| 2318 |
+
if child_state["stage"] == "RUNNING_APP_STARTING":
|
| 2319 |
+
parts.append(f"\n🔴 INVASIVE DIAGNOSTICS REQUIRED:")
|
| 2320 |
+
parts.append(f"{CHILD_NAME} is DEADLOCKED in APP_STARTING state!")
|
| 2321 |
+
parts.append(f"⛑️ CHECK THE 'INVASIVE DIAGNOSTICS' SECTION ABOVE — it contains ACTUAL crash logs from runtime!")
|
| 2322 |
+
parts.append(f"🛑 DO NOT hypothesize based on source code reading. The crash logs tell you the TRUTH.")
|
| 2323 |
+
parts.append(f"📋 Your [TASK] must address the SPECIFIC Python Exception shown in the diagnostics.")
|
| 2324 |
+
parts.append(f"🚨 PUSH a fix NOW. Trial-and-error > 10 turns of discussion.")
|
| 2325 |
+
|
| 2326 |
# Add recent task reminder during cooldown/building
|
| 2327 |
if recent_task_reminder:
|
| 2328 |
last_completed, last_by, last_at = recent_task_reminder
|