mirror of https://github.com/kortix-ai/suna.git
wip
This commit is contained in:
parent
a7f0044d1d
commit
45ad00089a
|
@ -5,6 +5,7 @@ from fastapi import FastAPI, UploadFile, File, HTTPException, APIRouter, Form, D
|
|||
from fastapi.responses import Response
|
||||
from pydantic import BaseModel
|
||||
|
||||
from sandbox.sandbox import get_or_start_sandbox
|
||||
from utils.logger import logger
|
||||
from utils.auth_utils import get_optional_user_id
|
||||
from services.supabase import DBConnection
|
||||
|
@ -90,12 +91,14 @@ async def get_sandbox_by_id_safely(client, sandbox_id: str):
|
|||
logger.error(f"No project found for sandbox ID: {sandbox_id}")
|
||||
raise HTTPException(status_code=404, detail="Sandbox not found - no project owns this sandbox ID")
|
||||
|
||||
project_id = project_result.data[0]['project_id']
|
||||
logger.debug(f"Found project {project_id} for sandbox {sandbox_id}")
|
||||
# project_id = project_result.data[0]['project_id']
|
||||
# logger.debug(f"Found project {project_id} for sandbox {sandbox_id}")
|
||||
|
||||
try:
|
||||
# Get the sandbox
|
||||
sandbox = await get_or_create_project_sandbox(client, project_id)
|
||||
sandbox = await get_or_start_sandbox(sandbox_id)
|
||||
# Extract just the sandbox object from the tuple (sandbox, sandbox_id, sandbox_pass)
|
||||
# sandbox = sandbox_tuple[0]
|
||||
|
||||
return sandbox
|
||||
except Exception as e:
|
||||
|
@ -133,46 +136,6 @@ async def create_file(
|
|||
logger.error(f"Error creating file in sandbox {sandbox_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
# For backward compatibility, keep the JSON version too
|
||||
@router.post("/sandboxes/{sandbox_id}/files/json")
|
||||
async def create_file_json(
|
||||
sandbox_id: str,
|
||||
file_request: dict,
|
||||
request: Request = None,
|
||||
user_id: Optional[str] = Depends(get_optional_user_id)
|
||||
):
|
||||
"""Create a file in the sandbox using JSON (legacy support)"""
|
||||
logger.info(f"Received JSON file creation request for sandbox {sandbox_id}, user_id: {user_id}")
|
||||
client = await db.client
|
||||
|
||||
# Verify the user has access to this sandbox
|
||||
await verify_sandbox_access(client, sandbox_id, user_id)
|
||||
|
||||
try:
|
||||
# Get sandbox using the safer method
|
||||
sandbox = await get_sandbox_by_id_safely(client, sandbox_id)
|
||||
|
||||
# Get file path and content
|
||||
path = file_request.get("path")
|
||||
content = file_request.get("content", "")
|
||||
|
||||
if not path:
|
||||
logger.error(f"Missing file path in request for sandbox {sandbox_id}")
|
||||
raise HTTPException(status_code=400, detail="File path is required")
|
||||
|
||||
# Convert string content to bytes
|
||||
if isinstance(content, str):
|
||||
content = content.encode('utf-8')
|
||||
|
||||
# Create file
|
||||
sandbox.fs.upload_file(path, content)
|
||||
logger.info(f"File created at {path} in sandbox {sandbox_id}")
|
||||
|
||||
return {"status": "success", "created": True, "path": path}
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating file in sandbox {sandbox_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.get("/sandboxes/{sandbox_id}/files")
|
||||
async def list_files(
|
||||
sandbox_id: str,
|
||||
|
@ -248,56 +211,57 @@ async def read_file(
|
|||
logger.error(f"Error reading file in sandbox {sandbox_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
|
||||
@router.post("/project/{project_id}/sandbox/ensure-active")
|
||||
async def ensure_project_sandbox_active(
|
||||
project_id: str,
|
||||
request: Request = None,
|
||||
user_id: Optional[str] = Depends(get_optional_user_id)
|
||||
):
|
||||
"""
|
||||
Ensure that a project's sandbox is active and running.
|
||||
Checks the sandbox status and starts it if it's not running.
|
||||
"""
|
||||
logger.info(f"Received ensure sandbox active request for project {project_id}, user_id: {user_id}")
|
||||
client = await db.client
|
||||
# Should happen on server-side fully
|
||||
# @router.post("/project/{project_id}/sandbox/ensure-active")
|
||||
# async def ensure_project_sandbox_active(
|
||||
# project_id: str,
|
||||
# request: Request = None,
|
||||
# user_id: Optional[str] = Depends(get_optional_user_id)
|
||||
# ):
|
||||
# """
|
||||
# Ensure that a project's sandbox is active and running.
|
||||
# Checks the sandbox status and starts it if it's not running.
|
||||
# """
|
||||
# logger.info(f"Received ensure sandbox active request for project {project_id}, user_id: {user_id}")
|
||||
# client = await db.client
|
||||
|
||||
# Find the project and sandbox information
|
||||
project_result = await client.table('projects').select('*').eq('project_id', project_id).execute()
|
||||
# # Find the project and sandbox information
|
||||
# project_result = await client.table('projects').select('*').eq('project_id', project_id).execute()
|
||||
|
||||
if not project_result.data or len(project_result.data) == 0:
|
||||
logger.error(f"Project not found: {project_id}")
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
# if not project_result.data or len(project_result.data) == 0:
|
||||
# logger.error(f"Project not found: {project_id}")
|
||||
# raise HTTPException(status_code=404, detail="Project not found")
|
||||
|
||||
project_data = project_result.data[0]
|
||||
# project_data = project_result.data[0]
|
||||
|
||||
# For public projects, no authentication is needed
|
||||
if not project_data.get('is_public'):
|
||||
# For private projects, we must have a user_id
|
||||
if not user_id:
|
||||
logger.error(f"Authentication required for private project {project_id}")
|
||||
raise HTTPException(status_code=401, detail="Authentication required for this resource")
|
||||
# # For public projects, no authentication is needed
|
||||
# if not project_data.get('is_public'):
|
||||
# # For private projects, we must have a user_id
|
||||
# if not user_id:
|
||||
# logger.error(f"Authentication required for private project {project_id}")
|
||||
# raise HTTPException(status_code=401, detail="Authentication required for this resource")
|
||||
|
||||
account_id = project_data.get('account_id')
|
||||
# account_id = project_data.get('account_id')
|
||||
|
||||
# Verify account membership
|
||||
if account_id:
|
||||
account_user_result = await client.schema('basejump').from_('account_user').select('account_role').eq('user_id', user_id).eq('account_id', account_id).execute()
|
||||
if not (account_user_result.data and len(account_user_result.data) > 0):
|
||||
logger.error(f"User {user_id} not authorized to access project {project_id}")
|
||||
raise HTTPException(status_code=403, detail="Not authorized to access this project")
|
||||
# # Verify account membership
|
||||
# if account_id:
|
||||
# account_user_result = await client.schema('basejump').from_('account_user').select('account_role').eq('user_id', user_id).eq('account_id', account_id).execute()
|
||||
# if not (account_user_result.data and len(account_user_result.data) > 0):
|
||||
# logger.error(f"User {user_id} not authorized to access project {project_id}")
|
||||
# raise HTTPException(status_code=403, detail="Not authorized to access this project")
|
||||
|
||||
try:
|
||||
# Get or create the sandbox
|
||||
logger.info(f"Ensuring sandbox is active for project {project_id}")
|
||||
sandbox, sandbox_id, sandbox_pass = await get_or_create_project_sandbox(client, project_id)
|
||||
# try:
|
||||
# # Get or create the sandbox
|
||||
# logger.info(f"Ensuring sandbox is active for project {project_id}")
|
||||
# sandbox, sandbox_id, sandbox_pass = await get_or_create_project_sandbox(client, project_id)
|
||||
|
||||
logger.info(f"Successfully ensured sandbox {sandbox_id} is active for project {project_id}")
|
||||
# logger.info(f"Successfully ensured sandbox {sandbox_id} is active for project {project_id}")
|
||||
|
||||
return {
|
||||
"status": "success",
|
||||
"sandbox_id": sandbox_id,
|
||||
"message": "Sandbox is active"
|
||||
}
|
||||
except Exception as e:
|
||||
logger.error(f"Error ensuring sandbox is active for project {project_id}: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=str(e))
|
||||
# return {
|
||||
# "status": "success",
|
||||
# "sandbox_id": sandbox_id,
|
||||
# "message": "Sandbox is active"
|
||||
# }
|
||||
# except Exception as e:
|
||||
# logger.error(f"Error ensuring sandbox is active for project {project_id}: {str(e)}")
|
||||
# raise HTTPException(status_code=500, detail=str(e))
|
||||
|
|
|
@ -183,52 +183,52 @@ export const getProject = async (projectId: string): Promise<Project> => {
|
|||
|
||||
console.log('Raw project data from database:', data);
|
||||
|
||||
// If project has a sandbox, ensure it's started
|
||||
if (data.sandbox?.id) {
|
||||
// Fire off sandbox activation without blocking
|
||||
const ensureSandboxActive = async () => {
|
||||
try {
|
||||
const {
|
||||
data: { session },
|
||||
} = await supabase.auth.getSession();
|
||||
// // If project has a sandbox, ensure it's started
|
||||
// if (data.sandbox?.id) {
|
||||
// // Fire off sandbox activation without blocking
|
||||
// const ensureSandboxActive = async () => {
|
||||
// try {
|
||||
// const {
|
||||
// data: { session },
|
||||
// } = await supabase.auth.getSession();
|
||||
|
||||
// For public projects, we don't need authentication
|
||||
const headers: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
};
|
||||
// // For public projects, we don't need authentication
|
||||
// const headers: Record<string, string> = {
|
||||
// 'Content-Type': 'application/json',
|
||||
// };
|
||||
|
||||
if (session?.access_token) {
|
||||
headers['Authorization'] = `Bearer ${session.access_token}`;
|
||||
}
|
||||
// if (session?.access_token) {
|
||||
// headers['Authorization'] = `Bearer ${session.access_token}`;
|
||||
// }
|
||||
|
||||
console.log(`Ensuring sandbox is active for project ${projectId}...`);
|
||||
const response = await fetch(
|
||||
`${API_URL}/project/${projectId}/sandbox/ensure-active`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers,
|
||||
},
|
||||
);
|
||||
// console.log(`Ensuring sandbox is active for project ${projectId}...`);
|
||||
// const response = await fetch(
|
||||
// `${API_URL}/project/${projectId}/sandbox/ensure-active`,
|
||||
// {
|
||||
// method: 'POST',
|
||||
// headers,
|
||||
// },
|
||||
// );
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response
|
||||
.text()
|
||||
.catch(() => 'No error details available');
|
||||
console.warn(
|
||||
`Failed to ensure sandbox is active: ${response.status} ${response.statusText}`,
|
||||
errorText,
|
||||
);
|
||||
} else {
|
||||
console.log('Sandbox activation successful');
|
||||
}
|
||||
} catch (sandboxError) {
|
||||
console.warn('Failed to ensure sandbox is active:', sandboxError);
|
||||
}
|
||||
};
|
||||
// if (!response.ok) {
|
||||
// const errorText = await response
|
||||
// .text()
|
||||
// .catch(() => 'No error details available');
|
||||
// console.warn(
|
||||
// `Failed to ensure sandbox is active: ${response.status} ${response.statusText}`,
|
||||
// errorText,
|
||||
// );
|
||||
// } else {
|
||||
// console.log('Sandbox activation successful');
|
||||
// }
|
||||
// } catch (sandboxError) {
|
||||
// console.warn('Failed to ensure sandbox is active:', sandboxError);
|
||||
// }
|
||||
// };
|
||||
|
||||
// Start the sandbox activation without awaiting
|
||||
ensureSandboxActive();
|
||||
}
|
||||
// // Start the sandbox activation without awaiting
|
||||
// ensureSandboxActive();
|
||||
// }
|
||||
|
||||
// Map database fields to our Project type
|
||||
const mappedProject: Project = {
|
||||
|
|
Loading…
Reference in New Issue