fix new page opening in browser; latest container wip

This commit is contained in:
marko-kraemer 2025-05-09 05:08:29 +02:00
parent 0b51c6507c
commit fead1c831b
7 changed files with 53 additions and 35 deletions

View File

@ -88,7 +88,7 @@ You'll need the following components:
- Redis database for caching and session management - Redis database for caching and session management
- Daytona sandbox for secure agent execution - Daytona sandbox for secure agent execution
- Python 3.11 for the API backend - Python 3.11 for the API backend
- API keys for LLM providers (Anthropic) - API keys for LLM providers (Anthropic, OpenRouter)
- Tavily API key for enhanced search capabilities - Tavily API key for enhanced search capabilities
- Firecrawl API key for web scraping capabilities - Firecrawl API key for web scraping capabilities
@ -99,23 +99,16 @@ You'll need the following components:
- Save your project's API URL, anon key, and service role key for later use - Save your project's API URL, anon key, and service role key for later use
- Install the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) - Install the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started)
2. **Redis**: Set up a Redis instance using one of these options: 2. **Redis**:
- [Upstash Redis](https://upstash.com/) (recommended for cloud deployments) - Go to the `/backend` folder
- Local installation: - Run `docker compose up redis`
- [Mac](https://formulae.brew.sh/formula/redis): `brew install redis`
- [Linux](https://redis.io/docs/getting-started/installation/install-redis-on-linux/): Follow distribution-specific instructions
- [Windows](https://redis.io/docs/getting-started/installation/install-redis-on-windows/): Use WSL2 or Docker
- Docker Compose (included in our setup):
- If you're using our Docker Compose setup, Redis is included and configured automatically
- No additional installation is needed
- Save your Redis connection details for later use (not needed if using Docker Compose)
3. **Daytona**: 3. **Daytona**:
- Create an account on [Daytona](https://app.daytona.io/) - Create an account on [Daytona](https://app.daytona.io/)
- Generate an API key from your account settings - Generate an API key from your account settings
- Go to [Images](https://app.daytona.io/dashboard/images) - Go to [Images](https://app.daytona.io/dashboard/images)
- Click "Add Image" - Click "Add Image"
- Enter `adamcohenhillel/kortix-suna:0.0.20` as the image name - Enter `kortix/suna:0.1` as the image name
- Set `/usr/bin/supervisord -n -c /etc/supervisor/conf.d/supervisord.conf` as the Entrypoint - Set `/usr/bin/supervisord -n -c /etc/supervisor/conf.d/supervisord.conf` as the Entrypoint
4. **LLM API Keys**: 4. **LLM API Keys**:

32
backend/sandbox/README.md Normal file
View File

@ -0,0 +1,32 @@
# Agent Sandbox
This directory contains the agent sandbox implementation - a Docker-based virtual environment that agents use as their own computer to execute tasks, access the web, and manipulate files.
## Overview
The sandbox provides a complete containerized Linux environment with:
- Chrome browser for web interactions
- VNC server for accessing the Web User
- Web server for serving content (port 8080) -> loading html files from the /workspace directory
- Full file system access
- Full sudo access
## Customizing the Sandbox
You can modify the sandbox environment for development or to add new capabilities:
1. Edit files in the `docker/` directory
2. Build a custom image:
```
cd backend/sandbox/docker
docker-compose build
```
3. Test your changes locally using docker-compose
## Using a Custom Image
To use your custom sandbox image:
1. Change the `image` parameter in `docker-compose.yml` (that defines the image name `kortix/suna:___`)
2. Update the same image name in `backend/sandbox/sandbox.py` in the `create_sandbox` function
3. If using Daytona for deployment, update the image reference there as well

View File

@ -7,7 +7,6 @@ from pydantic import BaseModel
from utils.logger import logger from utils.logger import logger
from utils.auth_utils import get_optional_user_id from utils.auth_utils import get_optional_user_id
from sandbox.sandbox import get_or_start_sandbox
from services.supabase import DBConnection from services.supabase import DBConnection
from agent.api import get_or_create_project_sandbox from agent.api import get_or_create_project_sandbox
@ -97,14 +96,8 @@ async def get_sandbox_by_id_safely(client, sandbox_id: str):
try: try:
# Get the sandbox # Get the sandbox
sandbox, retrieved_sandbox_id, sandbox_pass = await get_or_create_project_sandbox(client, project_id) sandbox = await get_or_create_project_sandbox(client, project_id)
# Verify we got the right sandbox
if retrieved_sandbox_id != sandbox_id:
logger.warning(f"Retrieved sandbox ID {retrieved_sandbox_id} doesn't match requested ID {sandbox_id} for project {project_id}")
# Fall back to the direct method if IDs don't match (shouldn't happen but just in case)
sandbox = await get_or_start_sandbox(sandbox_id)
return sandbox return sandbox
except Exception as e: except Exception as e:
logger.error(f"Error retrieving sandbox {sandbox_id}: {str(e)}") logger.error(f"Error retrieving sandbox {sandbox_id}: {str(e)}")

View File

@ -1,10 +1,11 @@
from fastapi import FastAPI, APIRouter, HTTPException, Body from fastapi import FastAPI, APIRouter, HTTPException, Body
from playwright.async_api import async_playwright, Browser, Page from playwright.async_api import async_playwright, Browser, Page, ElementHandle
from pydantic import BaseModel from pydantic import BaseModel
from typing import Optional, List, Dict, Any from typing import Optional, List, Dict, Any, Union
import asyncio import asyncio
import json import json
import logging import logging
import re
import base64 import base64
from dataclasses import dataclass, field from dataclasses import dataclass, field
from datetime import datetime from datetime import datetime
@ -356,13 +357,13 @@ class BrowserAutomation:
self.current_page_index = 0 self.current_page_index = 0
except Exception as page_error: except Exception as page_error:
print(f"Error finding existing page, creating new one. ( {page_error})") print(f"Error finding existing page, creating new one. ( {page_error})")
page = await self.browser.new_page() # page = await self.browser.new_page()
print("New page created successfully") print("New page created successfully")
self.pages.append(page) # self.pages.append(page)
self.current_page_index = 0 self.current_page_index = 0
# Navigate to about:blank to ensure page is ready # Navigate to about:blank to ensure page is ready
# await page.goto("google.com", timeout=30000) # await page.goto("google.com", timeout=30000)
print("Navigated to google.com") # print("Navigated to google.com")
print("Browser initialization completed successfully") print("Browser initialization completed successfully")
except Exception as e: except Exception as e:

View File

@ -6,7 +6,7 @@ services:
dockerfile: ${DOCKERFILE:-Dockerfile} dockerfile: ${DOCKERFILE:-Dockerfile}
args: args:
TARGETPLATFORM: ${TARGETPLATFORM:-linux/amd64} TARGETPLATFORM: ${TARGETPLATFORM:-linux/amd64}
image: adamcohenhillel/kortix-suna:0.0.20 image: kortix/suna:0.1
ports: ports:
- "6080:6080" # noVNC web interface - "6080:6080" # noVNC web interface
- "5901:5901" # VNC port - "5901:5901" # VNC port

View File

@ -1,6 +1,5 @@
fastapi==0.115.12 fastapi
uvicorn==0.34.0 uvicorn
pyautogui==0.9.54 pillow
pillow==10.2.0 pydantic
pydantic==2.6.1 pytesseract
pytesseract==0.3.13

View File

@ -97,7 +97,7 @@ def create_sandbox(password: str, project_id: str = None):
labels = {'id': project_id} labels = {'id': project_id}
params = CreateSandboxParams( params = CreateSandboxParams(
image="adamcohenhillel/kortix-suna:0.0.20", image="kortix/suna:0.1",
public=True, public=True,
labels=labels, labels=labels,
env_vars={ env_vars={
@ -169,7 +169,7 @@ class SandboxToolsBase(Tool):
self._sandbox_pass = sandbox_info.get('pass') self._sandbox_pass = sandbox_info.get('pass')
# Get or start the sandbox # Get or start the sandbox
self._sandbox = await get_or_start_sandbox(self._sandbox_id) # self._sandbox = await get_or_start_sandbox(self._sandbox_id)
# # Log URLs if not already printed # # Log URLs if not already printed
# if not SandboxToolsBase._urls_printed: # if not SandboxToolsBase._urls_printed: