free-claude-code/wrapper/api.py
2026-01-28 18:47:45 -08:00

82 lines
2.7 KiB
Python

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from wrapper.cli_session import CLISession
from wrapper.parser import CLIParser
import os
import uvicorn
import logging
from dotenv import load_dotenv
# Load .env from the root directory
load_dotenv()
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = FastAPI()
# Configuration from environment
workspace_env = os.getenv("CLAUDE_WORKSPACE", "agent_workspace")
WORKSPACE = os.path.normpath(os.path.abspath(workspace_env))
print(f"--- WRAPPER CONFIG ---", flush=True)
print(f"WORKSPACE: {WORKSPACE}", flush=True)
# The proxy server is running on port 8082 based on user context
API_URL = os.getenv("ANTHROPIC_API_URL", "http://localhost:8082/v1")
ALLOWED_DIRS = os.getenv("ALLOWED_DIRS", "").split(",")
ALLOWED_DIRS = [os.path.normpath(d.strip()) for d in ALLOWED_DIRS if d.strip()]
print(f"ALLOWED_DIRS: {ALLOWED_DIRS}", flush=True)
session = CLISession(WORKSPACE, API_URL, ALLOWED_DIRS)
@app.post("/stop")
async def stop_session():
"""Forcefully terminates the current Claude CLI process."""
if session.process and session.process.returncode is None:
logger.info("Forcefully terminating Claude process...")
try:
session.process.terminate()
return {"status": "terminated"}
except Exception as e:
return {"status": "error", "message": str(e)}
return {"status": "no_active_process"}
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
logger.info("Bot connected to WebSocket")
try:
while True:
# Receive task from bot
data = await websocket.receive_json()
task = data.get("task")
if not task:
continue
logger.info(f"Received task: {task}")
# Start Claude session and stream events back
async for event in session.start_task(task):
parsed = CLIParser.parse_event(event)
if parsed:
await websocket.send_json(parsed)
else:
# Send raw for debugging if it's unknown but relevant
if event.get("type") in ["system", "result"]:
await websocket.send_json(
{"type": "status", "data": event.get("subtype") or "update"}
)
except WebSocketDisconnect:
logger.info("Bot disconnected")
except Exception as e:
logger.error(f"Error in WebSocket: {e}")
await websocket.close()
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8083)