Spaces:
Sleeping
Sleeping
Claude Code commited on
Commit ·
c652463
1
Parent(s): a05e0c7
Claude Code: [TASK] Investigate Cain's error logs and diagnose the actual issue. Chec
Browse files- app.py +53 -72
- openclaw/.openclaw/agents/cain_status.json +7 -7
app.py
CHANGED
|
@@ -26,29 +26,43 @@ elif 'CAIN_STATUS_PATH' not in os.environ:
|
|
| 26 |
os.environ['CAIN_STATUS_PATH'] = '/data/cain_status.json'
|
| 27 |
print(f">>> CAIN: Set CAIN_STATUS_PATH (fallback) = {os.environ['CAIN_STATUS_PATH']}", flush=True)
|
| 28 |
|
| 29 |
-
# CRITICAL: Immediately clean stale "unknown" error from
|
| 30 |
# This must happen BEFORE any health checks read the status file
|
|
|
|
| 31 |
_status_path = os.environ.get('CAIN_STATUS_PATH', '/data/cain_status.json')
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
# CRITICAL: Create FastAPI app at TOP LEVEL, outside any try/except
|
| 54 |
# This ensures the server ALWAYS starts, even if brain is broken
|
|
@@ -471,60 +485,27 @@ try:
|
|
| 471 |
# Add explanatory note about error field semantics
|
| 472 |
status_data["_note"] = "error=null means healthy - null or 'unknown' string are both treated as 'no error'"
|
| 473 |
|
| 474 |
-
# Write to
|
| 475 |
-
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
|
| 481 |
-
|
| 482 |
-
# CRITICAL: Write to ALL possible locations to ensure "unknown" errors are cleared everywhere
|
| 483 |
-
_script_dir = Path(os.path.abspath(os.path.dirname(__file__)))
|
| 484 |
-
_possible_status_paths = [
|
| 485 |
-
Path("/app/openclaw/.openclaw/agents/cain_status.json"), # Nested structure (Docker)
|
| 486 |
-
Path("/app/.openclaw/agents/cain_status.json"), # Legacy flat structure
|
| 487 |
-
Path("/app/cain_status.json"), # App root
|
| 488 |
-
Path("/app/data/cain_status.json"), # App data subdirectory
|
| 489 |
-
_script_dir / "openclaw" / ".openclaw" / "agents" / "cain_status.json",
|
| 490 |
-
_script_dir / ".openclaw" / "agents" / "cain_status.json",
|
| 491 |
]
|
| 492 |
-
|
|
|
|
|
|
|
| 493 |
try:
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
try:
|
| 499 |
-
with open(p, 'r') as f:
|
| 500 |
-
existing_data = json.load(f)
|
| 501 |
-
# CRITICAL: Always overwrite if it has a stale "unknown" error, regardless of timestamp
|
| 502 |
-
existing_error = existing_data.get('error')
|
| 503 |
-
has_stale_error = (
|
| 504 |
-
isinstance(existing_error, str) and
|
| 505 |
-
existing_error.strip().lower() in ('unknown', 'none', 'null', '')
|
| 506 |
-
)
|
| 507 |
-
if has_stale_error:
|
| 508 |
-
with open(p, 'w') as f:
|
| 509 |
-
json.dump(status_data, f, indent=2)
|
| 510 |
-
print(f">>> CAIN: Cleaned stale 'unknown' error at {p}", flush=True)
|
| 511 |
-
# Also update if our status is newer
|
| 512 |
-
elif status_data.get('last_updated', '') > existing_data.get('last_updated', ''):
|
| 513 |
-
with open(p, 'w') as f:
|
| 514 |
-
json.dump(status_data, f, indent=2)
|
| 515 |
-
print(f">>> CAIN: Updated status at {p}", flush=True)
|
| 516 |
-
except json.JSONDecodeError:
|
| 517 |
-
# File exists but is corrupted - overwrite with clean data
|
| 518 |
-
with open(p, 'w') as f:
|
| 519 |
-
json.dump(status_data, f, indent=2)
|
| 520 |
-
print(f">>> CAIN: Fixed corrupted status file at {p}", flush=True)
|
| 521 |
-
else:
|
| 522 |
-
# File doesn't exist - create it with clean data
|
| 523 |
-
with open(p, 'w') as f:
|
| 524 |
-
json.dump(status_data, f, indent=2)
|
| 525 |
-
print(f">>> CAIN: Created new status file at {p}", flush=True)
|
| 526 |
except Exception as e:
|
| 527 |
-
print(f">>> CAIN WARNING: Could not write to {
|
|
|
|
|
|
|
| 528 |
except Exception as e:
|
| 529 |
print(f">>> CAIN WARNING: Could not update status file: {e}", flush=True)
|
| 530 |
|
|
|
|
| 26 |
os.environ['CAIN_STATUS_PATH'] = '/data/cain_status.json'
|
| 27 |
print(f">>> CAIN: Set CAIN_STATUS_PATH (fallback) = {os.environ['CAIN_STATUS_PATH']}", flush=True)
|
| 28 |
|
| 29 |
+
# CRITICAL: Immediately clean stale "unknown" error from ALL status file locations
|
| 30 |
# This must happen BEFORE any health checks read the status file
|
| 31 |
+
# Fix for: Cain has RUNNING! Error: unknown - status files had stale error
|
| 32 |
_status_path = os.environ.get('CAIN_STATUS_PATH', '/data/cain_status.json')
|
| 33 |
+
_all_status_paths = [
|
| 34 |
+
Path(_status_path), # Primary (OPENCLAW_DATA_DIR)
|
| 35 |
+
Path('/app/openclaw/.openclaw/agents/cain_status.json'), # Nested structure
|
| 36 |
+
Path('/app/.openclaw/agents/cain_status.json'), # Legacy flat structure
|
| 37 |
+
Path('/app/cain_status.json'), # App root
|
| 38 |
+
Path('/app/data/cain_status.json'), # App data subdirectory
|
| 39 |
+
Path(__file__).parent / 'memory' / 'cain_status.json', # Memory directory
|
| 40 |
+
]
|
| 41 |
+
|
| 42 |
+
_cleaned_count = 0
|
| 43 |
+
for _sp in _all_status_paths:
|
| 44 |
+
try:
|
| 45 |
+
if _sp.exists():
|
| 46 |
+
with open(_sp, 'r') as f:
|
| 47 |
+
_status_data = json.load(f)
|
| 48 |
+
_error = _status_data.get('error')
|
| 49 |
+
# Clean if error is a "null" string (unknown, none, null, empty)
|
| 50 |
+
if isinstance(_error, str) and _error.strip().lower() in ('unknown', 'none', 'null', ''):
|
| 51 |
+
_status_data['error'] = None
|
| 52 |
+
_status_data['_cleaned_at'] = 'app_module_load_aggressive'
|
| 53 |
+
_status_data['_cleaned_path'] = str(_sp)
|
| 54 |
+
with open(_sp, 'w') as f:
|
| 55 |
+
json.dump(_status_data, f, indent=2)
|
| 56 |
+
_cleaned_count += 1
|
| 57 |
+
print(f">>> CAIN: Cleaned stale '{_error}' error from {_sp}", flush=True)
|
| 58 |
+
elif _error is None:
|
| 59 |
+
print(f">>> CAIN: Status OK: {_sp}", flush=True)
|
| 60 |
+
else:
|
| 61 |
+
print(f">>> CAIN: Status has real error at {_sp}: {_error}", flush=True)
|
| 62 |
+
except Exception as e:
|
| 63 |
+
print(f">>> CAIN: Could not clean {_sp}: {e}", flush=True)
|
| 64 |
+
|
| 65 |
+
print(f">>> CAIN: Cleaned {_cleaned_count} status file(s) at module load", flush=True)
|
| 66 |
|
| 67 |
# CRITICAL: Create FastAPI app at TOP LEVEL, outside any try/except
|
| 68 |
# This ensures the server ALWAYS starts, even if brain is broken
|
|
|
|
| 485 |
# Add explanatory note about error field semantics
|
| 486 |
status_data["_note"] = "error=null means healthy - null or 'unknown' string are both treated as 'no error'"
|
| 487 |
|
| 488 |
+
# Write to ALL possible locations to ensure consistency and prevent stale errors
|
| 489 |
+
all_status_paths = [
|
| 490 |
+
os.environ.get('CAIN_STATUS_PATH', '/data/cain_status.json'),
|
| 491 |
+
'/app/openclaw/.openclaw/agents/cain_status.json',
|
| 492 |
+
'/app/.openclaw/agents/cain_status.json',
|
| 493 |
+
'/app/cain_status.json',
|
| 494 |
+
'/app/data/cain_status.json',
|
| 495 |
+
os.path.join(os.path.dirname(__file__), 'memory', 'cain_status.json'),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 496 |
]
|
| 497 |
+
|
| 498 |
+
written_count = 0
|
| 499 |
+
for status_path in all_status_paths:
|
| 500 |
try:
|
| 501 |
+
Path(status_path).parent.mkdir(parents=True, exist_ok=True)
|
| 502 |
+
with open(status_path, 'w') as f:
|
| 503 |
+
json.dump(status_data, f, indent=2)
|
| 504 |
+
written_count += 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
except Exception as e:
|
| 506 |
+
print(f">>> CAIN WARNING: Could not write to {status_path}: {e}", flush=True)
|
| 507 |
+
|
| 508 |
+
print(f">>> CAIN: Status file written to {written_count} location(s): stage=RUNNING_A2A_READY, error=None", flush=True)
|
| 509 |
except Exception as e:
|
| 510 |
print(f">>> CAIN WARNING: Could not update status file: {e}", flush=True)
|
| 511 |
|
openclaw/.openclaw/agents/cain_status.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
| 1 |
{
|
| 2 |
"current_state": "idle",
|
| 3 |
-
"
|
| 4 |
-
"last_updated": "2026-03-16T16:30:00.000000+00:00",
|
| 5 |
"agent": "cain",
|
| 6 |
"error": null,
|
| 7 |
-
"
|
| 8 |
-
|
| 9 |
-
"brain_imported": true
|
| 10 |
-
},
|
| 11 |
"a2a": {
|
| 12 |
"endpoint": "/a2a/jsonrpc",
|
| 13 |
"enabled": true,
|
| 14 |
"status": "ready",
|
| 15 |
"brain_ready": true
|
| 16 |
},
|
| 17 |
-
"
|
|
|
|
|
|
|
|
|
|
| 18 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"current_state": "idle",
|
| 3 |
+
"last_updated": "2026-03-16T20:24:46.319956+00:00",
|
|
|
|
| 4 |
"agent": "cain",
|
| 5 |
"error": null,
|
| 6 |
+
"_note": "error=null means healthy - treated as 'no error'",
|
| 7 |
+
"stage": "RUNNING_A2A_READY",
|
|
|
|
|
|
|
| 8 |
"a2a": {
|
| 9 |
"endpoint": "/a2a/jsonrpc",
|
| 10 |
"enabled": true,
|
| 11 |
"status": "ready",
|
| 12 |
"brain_ready": true
|
| 13 |
},
|
| 14 |
+
"startup_checks": {
|
| 15 |
+
"openclaw_imported": true,
|
| 16 |
+
"brain_imported": true
|
| 17 |
+
}
|
| 18 |
}
|