docs: Comprehensive documentation update for Dashboard V3 and Canvas

## Documentation Updates
- DASHBOARD.md: Updated to V3.0 with Canvas V3 features, file browser, introspection
- DASHBOARD_IMPLEMENTATION_STATUS.md: Marked Canvas V3 features as COMPLETE
- CANVAS.md: New comprehensive guide for Canvas Builder V3 with all features
- CLAUDE.md: Added dashboard quick reference and Canvas V3 features

## Canvas V3 Features Documented
- File Browser: Browse studies directory for model files
- Model Introspection: Auto-discover expressions, solver type, dependencies
- One-Click Add: Add expressions as design variables instantly
- Claude Bug Fixes: WebSocket reconnection, SQL errors resolved
- Health Check: /api/health endpoint for monitoring

## Backend Services
- NX introspection service with expression discovery
- File browser API with type filtering
- Claude session management improvements
- Context builder enhancements

## Frontend Components
- FileBrowser: Modal for file selection with search
- IntrospectionPanel: View discovered model information
- ExpressionSelector: Dropdown for design variable configuration
- Improved chat hooks with reconnection logic

## Plan Documents
- Added RALPH_LOOP_CANVAS_V2/V3 implementation records
- Added ATOMIZER_DASHBOARD_V2_MASTER_PLAN
- Added investigation and sync documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-16 20:48:58 -05:00
parent 1c7c7aff05
commit ac5e9b4054
23 changed files with 10860 additions and 773 deletions

View File

@@ -93,7 +93,10 @@ async def create_session(request: CreateSessionRequest):
"is_alive": session.is_alive(),
}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
import traceback
error_msg = f"{type(e).__name__}: {str(e) or 'No message'}"
traceback.print_exc()
raise HTTPException(status_code=500, detail=error_msg)
@router.get("/sessions/{session_id}")
@@ -146,8 +149,9 @@ async def session_websocket(websocket: WebSocket, session_id: str):
WebSocket for real-time chat with a session.
Message formats (client -> server):
{"type": "message", "content": "user message"}
{"type": "message", "content": "user message", "canvas_state": {...}}
{"type": "set_study", "study_id": "study_name"}
{"type": "set_canvas", "canvas_state": {...}}
{"type": "ping"}
Message formats (server -> client):
@@ -158,6 +162,7 @@ async def session_websocket(websocket: WebSocket, session_id: str):
{"type": "error", "message": "..."}
{"type": "pong"}
{"type": "context_updated", "study_id": "..."}
{"type": "canvas_updated", "canvas_state": {...}}
"""
await websocket.accept()
@@ -169,6 +174,9 @@ async def session_websocket(websocket: WebSocket, session_id: str):
await websocket.close()
return
# Track current canvas state for this connection
current_canvas_state: Dict[str, Any] = {}
try:
while True:
data = await websocket.receive_json()
@@ -178,7 +186,14 @@ async def session_websocket(websocket: WebSocket, session_id: str):
if not content:
continue
async for chunk in manager.send_message(session_id, content):
# Get canvas state from message or use stored state
canvas_state = data.get("canvas_state") or current_canvas_state
async for chunk in manager.send_message(
session_id,
content,
canvas_state=canvas_state if canvas_state else None,
):
await websocket.send_json(chunk)
elif data.get("type") == "set_study":
@@ -190,6 +205,14 @@ async def session_websocket(websocket: WebSocket, session_id: str):
"study_id": study_id,
})
elif data.get("type") == "set_canvas":
# Update canvas state for this connection
current_canvas_state = data.get("canvas_state", {})
await websocket.send_json({
"type": "canvas_updated",
"canvas_state": current_canvas_state,
})
elif data.get("type") == "ping":
await websocket.send_json({"type": "pong"})