From e0fb0235dff70c642440582f9a3fd4da72fa480b Mon Sep 17 00:00:00 2001 From: Dillon DuPont Date: Wed, 27 Aug 2025 15:33:32 -0400 Subject: [PATCH] Added CORS headers --- libs/python/agent/agent/proxy/examples.py | 39 ++++++++---- .../computer-server/computer_server/main.py | 59 ++++++++++++++++++- 2 files changed, 84 insertions(+), 14 deletions(-) diff --git a/libs/python/agent/agent/proxy/examples.py b/libs/python/agent/agent/proxy/examples.py index 238fc77a..2838c5df 100644 --- a/libs/python/agent/agent/proxy/examples.py +++ b/libs/python/agent/agent/proxy/examples.py @@ -1,9 +1,12 @@ """ Example usage of the proxy server and client requests. """ +import dotenv +dotenv.load_dotenv() import asyncio import json +import os import aiohttp from typing import Dict, Any @@ -11,10 +14,16 @@ from typing import Dict, Any async def test_http_endpoint(): """Test the HTTP /responses endpoint.""" + anthropic_api_key = os.getenv("ANTHROPIC_API_KEY") + assert isinstance(anthropic_api_key, str), "ANTHROPIC_API_KEY environment variable must be set" + # Example 1: Simple text request simple_request = { "model": "anthropic/claude-3-5-sonnet-20241022", - "input": "Tell me a three sentence bedtime story about a unicorn." + "input": "Tell me a three sentence bedtime story about a unicorn.", + "env": { + "ANTHROPIC_API_KEY": anthropic_api_key + } } # Example 2: Multi-modal request with image @@ -31,36 +40,42 @@ async def test_http_endpoint(): } ] } - ] + ], + "env": { + "ANTHROPIC_API_KEY": anthropic_api_key + } } # Example 3: Request with custom agent and computer kwargs custom_request = { "model": "anthropic/claude-3-5-sonnet-20241022", "input": "Take a screenshot and tell me what you see", - "agent_kwargs": { - "save_trajectory": True, - "verbosity": 20 # INFO level - }, - "computer_kwargs": { - "os_type": "linux", - "provider_type": "cloud" + "env": { + "ANTHROPIC_API_KEY": anthropic_api_key } } # Test requests - base_url = "http://localhost:8000" + base_url = "https://m-linux-96lcxd2c2k.containers.cloud.trycua.com:8443" + # base_url = "http://localhost:8000" + api_key = os.getenv("CUA_API_KEY") + assert isinstance(api_key, str), "CUA_API_KEY environment variable must be set" async with aiohttp.ClientSession() as session: - for i, request_data in enumerate([simple_request, multimodal_request, custom_request], 1): + for i, request_data in enumerate([ + simple_request, + # multimodal_request, + custom_request + ], 1): print(f"\n--- Test {i} ---") print(f"Request: {json.dumps(request_data, indent=2)}") try: + print(f"Sending request to {base_url}/responses") async with session.post( f"{base_url}/responses", json=request_data, - headers={"Content-Type": "application/json"} + headers={"Content-Type": "application/json", "X-API-Key": api_key} ) as response: result = await response.json() print(f"Status: {response.status}") diff --git a/libs/python/computer-server/computer_server/main.py b/libs/python/computer-server/computer_server/main.py index 106f906f..491b12c2 100644 --- a/libs/python/computer-server/computer_server/main.py +++ b/libs/python/computer-server/computer_server/main.py @@ -1,5 +1,5 @@ from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, HTTPException, Header -from fastapi.responses import StreamingResponse +from fastapi.responses import StreamingResponse, JSONResponse from typing import List, Dict, Any, Optional, Union, Literal, cast import uvicorn import logging @@ -650,13 +650,68 @@ async def agent_response_endpoint( if turns > 2: break - return { + # Build response payload + payload = { "success": True, "model": model, "output": total_output, "usage": total_usage, } + # Set CORS headers for allowed origins only + origin = request.headers.get("origin") + allowed_origins = { + "http://localhost", + "http://localhost:3000", + "http://localhost:5173", + "http://127.0.0.1", + "http://127.0.0.1:3000", + "https://trycua.com", + "https://www.trycua.com", + } + + headers = { + "Cache-Control": "no-cache", + "Connection": "keep-alive", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, X-Container-Name, X-API-Key", + } + if origin and origin in allowed_origins: + headers["Access-Control-Allow-Origin"] = origin + headers["Vary"] = "Origin" + + return JSONResponse(content=payload, headers=headers) + + +@app.options("/responses") +async def agent_response_options(request: Request): + """CORS preflight for /responses""" + origin = request.headers.get("origin") + allowed_origins = { + "http://localhost", + "http://localhost:3000", + "http://localhost:3001", + "http://localhost:5173", + "http://127.0.0.1", + "http://127.0.0.1:3000", + "http://127.0.0.1:3001", + "https://trycua.com", + "https://www.trycua.com", + } + + headers = { + "Cache-Control": "no-cache", + "Connection": "keep-alive", + "Access-Control-Allow-Methods": "POST, OPTIONS", + "Access-Control-Allow-Headers": "Content-Type, X-Container-Name, X-API-Key", + "Access-Control-Max-Age": "600", + } + if origin and origin in allowed_origins: + headers["Access-Control-Allow-Origin"] = origin + headers["Vary"] = "Origin" + + return JSONResponse(content={}, headers=headers) + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000)