Claude Code commited on
Commit
2be8520
·
1 Parent(s): c4be211

Auto-push: Discussion loop verification (turn 3)

Browse files
Files changed (2) hide show
  1. app.py +4 -32
  2. error_handlers.py +112 -0
app.py CHANGED
@@ -9,7 +9,6 @@ from fastapi.staticfiles import StaticFiles
9
  from fastapi.responses import FileResponse
10
  from fastapi import WebSocket
11
  from pydantic import BaseModel
12
- import json
13
  import os
14
  import sys
15
  from datetime import datetime
@@ -21,6 +20,8 @@ sys.path.insert(0, "/app")
21
 
22
  # Import system logger
23
  from openclaw.core.system_logger import log_startup, log_heartbeat, get_last_lines
 
 
24
 
25
 
26
  @asynccontextmanager
@@ -63,47 +64,18 @@ app.add_middleware(
63
  allow_headers=["*"],
64
  )
65
 
66
- # Paths
67
- OPENCLAW_DIR = "/app/.openclaw"
68
- STATUS_FILE = f"{OPENCLAW_DIR}/agents/cain_status.json"
69
-
70
-
71
  class ChatMessage(BaseModel):
72
  message: str
73
 
74
 
75
  def get_cain_status() -> dict:
76
  """Read Cain's current status from cain_status.json."""
77
- try:
78
- with open(STATUS_FILE, "r") as f:
79
- return json.load(f)
80
- except FileNotFoundError:
81
- return {
82
- "current_state": "unknown",
83
- "last_updated": datetime.utcnow().isoformat() + "+00:00",
84
- "agent": "cain"
85
- }
86
 
87
 
88
  def get_brain_response(message: str) -> str:
89
  """Route message to brain_minimal.py and return response."""
90
- try:
91
- # Import brain module from openclaw package
92
- from openclaw.agents.brain_minimal import BrainMinimal
93
-
94
- # Create brain instance for Cain
95
- brain = BrainMinimal(agent_name="cain", legacy_mode=True)
96
-
97
- # Process the message using conversation_process
98
- result = brain._conversation_process(message)
99
-
100
- # Return the response text
101
- if result.get("success"):
102
- return result.get("response", f"Processed: {message}")
103
- else:
104
- return f"Error: {result.get('error', 'Unknown error')}"
105
- except Exception as e:
106
- return f"Brain error: {str(e)}"
107
 
108
 
109
  @app.get("/", response_class=FileResponse)
 
9
  from fastapi.responses import FileResponse
10
  from fastapi import WebSocket
11
  from pydantic import BaseModel
 
12
  import os
13
  import sys
14
  from datetime import datetime
 
20
 
21
  # Import system logger
22
  from openclaw.core.system_logger import log_startup, log_heartbeat, get_last_lines
23
+ # Import error handlers
24
+ from error_handlers import handle_status_file_read, handle_brain_response, handle_websocket_message
25
 
26
 
27
  @asynccontextmanager
 
64
  allow_headers=["*"],
65
  )
66
 
 
 
 
 
 
67
  class ChatMessage(BaseModel):
68
  message: str
69
 
70
 
71
  def get_cain_status() -> dict:
72
  """Read Cain's current status from cain_status.json."""
73
+ return handle_status_file_read()
 
 
 
 
 
 
 
 
74
 
75
 
76
  def get_brain_response(message: str) -> str:
77
  """Route message to brain_minimal.py and return response."""
78
+ return handle_brain_response(message)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
 
80
 
81
  @app.get("/", response_class=FileResponse)
error_handlers.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """
3
+ Error handling utilities for HuggingClaw - Cain.
4
+ Provides specific exception handlers for common operations.
5
+ """
6
+ import json
7
+ import os
8
+ from datetime import datetime
9
+ from typing import Dict, Any, Optional
10
+
11
+
12
+ # Configuration paths
13
+ OPENCLAW_DIR = "/app/.openclaw"
14
+ STATUS_FILE = f"{OPENCLAW_DIR}/agents/cain_status.json"
15
+
16
+
17
+ def handle_status_file_read() -> Dict[str, Any]:
18
+ """
19
+ Handle reading Cain's status file with specific exception handling.
20
+
21
+ Returns:
22
+ Status dictionary with current_state, last_updated, and agent fields.
23
+
24
+ Raises:
25
+ PermissionError: If file exists but cannot be read due to permissions.
26
+ json.JSONDecodeError: If file contains invalid JSON.
27
+ """
28
+ try:
29
+ with open(STATUS_FILE, "r") as f:
30
+ return json.load(f)
31
+ except FileNotFoundError:
32
+ return {
33
+ "current_state": "unknown",
34
+ "last_updated": datetime.utcnow().isoformat() + "+00:00",
35
+ "agent": "cain"
36
+ }
37
+ except PermissionError as e:
38
+ return {
39
+ "current_state": "error",
40
+ "last_updated": datetime.utcnow().isoformat() + "+00:00",
41
+ "agent": "cain",
42
+ "error": f"Permission denied reading status file: {str(e)}"
43
+ }
44
+ except json.JSONDecodeError as e:
45
+ return {
46
+ "current_state": "error",
47
+ "last_updated": datetime.utcnow().isoformat() + "+00:00",
48
+ "agent": "cain",
49
+ "error": f"Invalid JSON in status file: {str(e)}"
50
+ }
51
+
52
+
53
+ def handle_brain_response(message: str) -> str:
54
+ """
55
+ Handle brain processing with specific exception handling.
56
+
57
+ Args:
58
+ message: The user message to process.
59
+
60
+ Returns:
61
+ Response string from the brain or error message.
62
+
63
+ Raises:
64
+ ImportError: If brain module cannot be imported.
65
+ AttributeError: If required brain methods are missing.
66
+ """
67
+ try:
68
+ from openclaw.agents.brain_minimal import BrainMinimal
69
+
70
+ brain = BrainMinimal(agent_name="cain", legacy_mode=True)
71
+ result = brain._conversation_process(message)
72
+
73
+ if result.get("success"):
74
+ return result.get("response", f"Processed: {message}")
75
+ else:
76
+ return f"Error: {result.get('error', 'Unknown error')}"
77
+
78
+ except ImportError as e:
79
+ return f"Brain module import error: {str(e)}"
80
+ except AttributeError as e:
81
+ return f"Brain interface error: {str(e)}"
82
+ except KeyError as e:
83
+ return f"Brain response format error: missing key {str(e)}"
84
+ except Exception as e:
85
+ return f"Brain processing error: {type(e).__name__}: {str(e)}"
86
+
87
+
88
+ def handle_websocket_message(websocket, status_func, sleep_func) -> bool:
89
+ """
90
+ Handle websocket message loop with specific exception handling.
91
+
92
+ Args:
93
+ websocket: The WebSocket connection object.
94
+ status_func: Function to get current status.
95
+ sleep_func: Async sleep function.
96
+
97
+ Returns:
98
+ True if loop should continue, False if it should break.
99
+ """
100
+ try:
101
+ status_data = status_func()
102
+ websocket.send_json({
103
+ "type": "heartbeat",
104
+ "status": status_data
105
+ })
106
+ return True
107
+ except ConnectionError:
108
+ return False
109
+ except RuntimeError:
110
+ return False
111
+ except Exception:
112
+ return False