openhands-backend / server.py
PYAE1994's picture
Update server with mock fallback and WebSocket proxy
97250c4 verified
Raw
History Blame Contribute Delete
3.41 kB
"""Proxy server to OpenHands Cloud API"""
import os
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import httpx
app = FastAPI(title="OpenHands Backend", version="1.0.0")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
OPENHANDS_API_KEY = os.getenv("OPENHANDS_API_KEY", "")
OPENHANDS_BASE_URL = os.getenv("OPENHANDS_BASE_URL", "https://app.all-hands.dev")
def get_headers():
return {"Authorization": f"Bearer {OPENHANDS_API_KEY}", "Content-Type": "application/json"}
@app.get("/health")
async def health():
return {"status": "ok", "backend": "cloud-proxy", "version": "1.0.0"}
@app.get("/ready")
async def ready():
return {"status": "ready", "service": "openhands-cloud-proxy", "api_key_configured": bool(OPENHANDS_API_KEY)}
@app.get("/server_info")
async def server_info():
return {
"version": "1.0.0",
"llm_proxy": os.getenv("LLM_PROXY_URL", "https://llm-proxy.app.all-hands.dev"),
"e2b_enabled": bool(os.getenv("E2B_API_KEY")),
"redis_enabled": False,
"supabase_enabled": False,
"openhands_cloud": True,
}
@app.get("/api/conversations")
async def list_conversations():
if not OPENHANDS_API_KEY:
# Return mock data for demo
return {"conversations": [], "mock": True}
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.get(
f"{OPENHANDS_BASE_URL}/api/conversations",
headers=get_headers()
)
resp.raise_for_status()
return resp.json()
@app.post("/api/conversations")
async def create_conversation(data: dict):
if not OPENHANDS_API_KEY:
# Return mock for demo
import uuid
return {"conversation_id": str(uuid.uuid4()), "message": "Mock response - configure API key for real agent", "mock": True}
async with httpx.AsyncClient(timeout=60.0) as client:
resp = await client.post(
f"{OPENHANDS_BASE_URL}/api/conversations",
headers=get_headers(),
json=data
)
resp.raise_for_status()
return resp.json()
@app.get("/api/conversations/{conv_id}")
async def get_conversation(conv_id: str):
if not OPENHANDS_API_KEY:
return {"id": conv_id, "messages": [], "mock": True}
async with httpx.AsyncClient(timeout=30.0) as client:
resp = await client.get(
f"{OPENHANDS_BASE_URL}/api/conversations/{conv_id}",
headers=get_headers()
)
resp.raise_for_status()
return resp.json()
@app.websocket("/ws/conversations/{conv_id}/events")
async def websocket_events(conv_id: str, websocket):
await websocket.accept()
if not OPENHANDS_API_KEY:
await websocket.send_json({"type": "error", "message": "API key not configured"})
await websocket.close()
return
# Proxy to OpenHands Cloud WebSocket
async with httpx.AsyncClient(timeout=httpx.Timeout(300.0)) as client:
async with client.stream(
"GET",
f"{OPENHANDS_BASE_URL}/ws/conversations/{conv_id}/events",
headers={"Authorization": f"Bearer {OPENHANDS_API_KEY}"}
) as resp:
async for line in resp.aiter_lines():
if line:
await websocket.send_text(line)