Claude Code Claude Opus 4.6 commited on
Commit
3f1c4cd
·
1 Parent(s): 95148ba

Claude Code: Add A2A diagnostics and fix stage reporting

Browse files

- Update status file to RUNNING_A2A_READY when app starts
- Add logging to /a2a/jsonrpc endpoint for debugging
- Add /a2a/self-test endpoint for A2A diagnostics
- Fix stage mismatch between status file and health checks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Files changed (1) hide show
  1. app.py +81 -0
app.py CHANGED
@@ -154,8 +154,10 @@ async def a2a_jsonrpc(request: Request):
154
 
155
  Handles message/send requests from other agents in the HuggingClaw World family.
156
  """
 
157
  try:
158
  payload = await request.json()
 
159
 
160
  # Validate JSON-RPC 2.0 basic structure
161
  if payload.get("jsonrpc") != "2.0":
@@ -274,6 +276,59 @@ async def api_status():
274
  }
275
 
276
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  # ============================================================================
278
  # A2A HEALTH CHECK ENDPOINT - For agents to verify Cain's A2A availability
279
  # ============================================================================
@@ -340,8 +395,34 @@ async def a2a_health():
340
  print(">>> CAIN: FastAPI app created successfully", flush=True)
341
  print(">>> CAIN: A2A endpoint registered at /a2a/jsonrpc", flush=True)
342
  print(">>> CAIN: A2A health check at /a2a/health", flush=True)
 
343
  print(">>> CAIN: A2A diagnostics at /a2a/diagnostics", flush=True)
344
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  # Verify openclaw can be imported at startup
346
  try:
347
  import openclaw
 
154
 
155
  Handles message/send requests from other agents in the HuggingClaw World family.
156
  """
157
+ print(f">>> CAIN A2A: Received request at {time.time()}", flush=True)
158
  try:
159
  payload = await request.json()
160
+ print(f">>> CAIN A2A: Payload method={payload.get('method')}, id={payload.get('id')}", flush=True)
161
 
162
  # Validate JSON-RPC 2.0 basic structure
163
  if payload.get("jsonrpc") != "2.0":
 
276
  }
277
 
278
 
279
+ # ============================================================================
280
+ # A2A SELF-TEST ENDPOINT - Test A2A endpoint without external agent
281
+ # ============================================================================
282
+ @app.get("/a2a/self-test")
283
+ async def a2a_self_test():
284
+ """
285
+ Self-test endpoint for A2A functionality.
286
+ Tests brain import and returns detailed status.
287
+ """
288
+ print(f">>> CAIN A2A: Self-test requested", flush=True)
289
+ test_results = {
290
+ "timestamp": time.time(),
291
+ "tests": {}
292
+ }
293
+
294
+ # Test 1: Can we import openclaw?
295
+ try:
296
+ import openclaw
297
+ test_results["tests"]["openclaw_import"] = {"status": "pass", "path": str(openclaw.__file__)}
298
+ except Exception as e:
299
+ test_results["tests"]["openclaw_import"] = {"status": "fail", "error": str(e)}
300
+
301
+ # Test 2: Can we import brain_minimal?
302
+ try:
303
+ from agents import brain_minimal
304
+ test_results["tests"]["brain_minimal_import"] = {"status": "pass"}
305
+ except Exception as e:
306
+ test_results["tests"]["brain_minimal_import"] = {"status": "fail", "error": str(e)}
307
+
308
+ # Test 3: Can we get a brain instance?
309
+ try:
310
+ from agents import brain_minimal
311
+ brain = brain_minimal.get_brain(agent_name="cain", legacy_mode=True)
312
+ test_results["tests"]["get_brain"] = {"status": "pass", "agent_name": getattr(brain, 'agent_name', 'unknown')}
313
+ except Exception as e:
314
+ test_results["tests"]["get_brain"] = {"status": "fail", "error": str(e)}
315
+
316
+ # Test 4: Can we call _conversation_process?
317
+ try:
318
+ from agents import brain_minimal
319
+ brain = brain_minimal.get_brain(agent_name="cain", legacy_mode=True)
320
+ result = brain._conversation_process("test")
321
+ test_results["tests"]["conversation_process"] = {"status": "pass", "success": result.get("success")}
322
+ except Exception as e:
323
+ test_results["tests"]["conversation_process"] = {"status": "fail", "error": str(e)}
324
+
325
+ # Overall status
326
+ all_pass = all(t.get("status") == "pass" for t in test_results["tests"].values())
327
+ test_results["overall_status"] = "pass" if all_pass else "partial_fail"
328
+
329
+ return test_results
330
+
331
+
332
  # ============================================================================
333
  # A2A HEALTH CHECK ENDPOINT - For agents to verify Cain's A2A availability
334
  # ============================================================================
 
395
  print(">>> CAIN: FastAPI app created successfully", flush=True)
396
  print(">>> CAIN: A2A endpoint registered at /a2a/jsonrpc", flush=True)
397
  print(">>> CAIN: A2A health check at /a2a/health", flush=True)
398
+ print(">>> CAIN: A2A self-test at /a2a/self-test", flush=True)
399
  print(">>> CAIN: A2A diagnostics at /a2a/diagnostics", flush=True)
400
 
401
+ # Update status file to indicate app is ready (A2A available)
402
+ try:
403
+ import json
404
+ from datetime import datetime
405
+ status_path = os.environ.get('CAIN_STATUS_PATH', '/data/cain_status.json')
406
+ status_data = {
407
+ "current_state": "idle",
408
+ "stage": "RUNNING_A2A_READY",
409
+ "last_updated": datetime.utcnow().isoformat() + "+00:00",
410
+ "agent": "cain",
411
+ "a2a": {
412
+ "endpoint": "/a2a/jsonrpc",
413
+ "enabled": True,
414
+ "status": "ready"
415
+ }
416
+ }
417
+ # Ensure directory exists
418
+ from pathlib import Path
419
+ Path(status_path).parent.mkdir(parents=True, exist_ok=True)
420
+ with open(status_path, 'w') as f:
421
+ json.dump(status_data, f, indent=2)
422
+ print(f">>> CAIN: Status file updated: stage=RUNNING_A2A_READY", flush=True)
423
+ except Exception as e:
424
+ print(f">>> CAIN WARNING: Could not update status file: {e}", flush=True)
425
+
426
  # Verify openclaw can be imported at startup
427
  try:
428
  import openclaw