mirror of https://github.com/kortix-ai/suna.git
website
This commit is contained in:
parent
17536b9714
commit
6be80eb7ff
|
@ -3,8 +3,9 @@ import json
|
|||
import uuid
|
||||
from agentpress.thread_manager import ThreadManager
|
||||
from agent.tools.files_tool import FilesTool
|
||||
from agent.tools.sb_browse_tool import SandboxTool
|
||||
from agent.tools.terminal_tool import TerminalTool
|
||||
from agent.tools.sb_browse_tool import SandboxBrowseTool
|
||||
from agent.tools.sb_shell_tool import SandboxShellTool
|
||||
from agent.tools.sb_website_tool import SandboxWebsiteTool
|
||||
# from agent.tools.search_tool import CodeSearchTool
|
||||
from typing import Optional
|
||||
from agent.prompt import get_system_prompt
|
||||
|
@ -22,16 +23,19 @@ async def run_agent(thread_id: str, stream: bool = True, thread_manager: Optiona
|
|||
thread_manager = ThreadManager()
|
||||
|
||||
if True: # todo: change to of not sandbox running
|
||||
sandbox = create_sandbox(TEMP_PASSWORD)
|
||||
sandbox = create_sandbox("vvv")
|
||||
sandbox_id = sandbox.id
|
||||
sandbox_password = "vvv"
|
||||
else:
|
||||
sandbox_id = "sandbox-01efaaa5"
|
||||
sandbox_password = "vvv"
|
||||
|
||||
print("Adding tools to thread manager...")
|
||||
# thread_manager.add_tool(FilesTool)
|
||||
# thread_manager.add_tool(TerminalTool)
|
||||
# thread_manager.add_tool(CodeSearchTool)
|
||||
thread_manager.add_tool(SandboxTool, sandbox_id=sandbox_id, password=sandbox_password)
|
||||
|
||||
# thread_manager.add_tool(SandboxBrowseTool, sandbox_id=sandbox_id, password=sandbox_password)
|
||||
thread_manager.add_tool(SandboxWebsiteTool, sandbox_id=sandbox_id, password=sandbox_password)
|
||||
system_message = {
|
||||
"role": "system",
|
||||
"content": get_system_prompt()
|
||||
|
|
|
@ -1,56 +1,96 @@
|
|||
from daytona_sdk.process import SessionExecuteRequest
|
||||
|
||||
from agentpress.tool import ToolResult, openapi_schema, xml_schema
|
||||
from agent.tools.utils.daytona_sandbox import SandboxToolsBase
|
||||
|
||||
|
||||
class SandboxWebsiteTool(SandboxToolsBase):
|
||||
"""Tool for executing tasks in a Daytona sandbox with browser-use capabilities."""
|
||||
|
||||
def __init__(self, sandbox_id: str, password: str):
|
||||
super().__init__(sandbox_id, password)
|
||||
|
||||
|
||||
@openapi_schema({
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "execute_command",
|
||||
"description": "Execute a shell command in the workspace directory",
|
||||
"name": "update_website_file",
|
||||
"description": "Upload or update a file in the website server's site directory",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"file_path": {
|
||||
"type": "string",
|
||||
"description": "The shell command to execute"
|
||||
"description": "Path where the file should be saved, relative to the site directory"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Content to write to the file"
|
||||
},
|
||||
"create_dirs": {
|
||||
"type": "boolean",
|
||||
"description": "Create parent directories if they don't exist",
|
||||
"default": True
|
||||
}
|
||||
},
|
||||
"required": ["command"]
|
||||
"required": ["file_path", "content"]
|
||||
}
|
||||
}
|
||||
})
|
||||
@xml_schema(
|
||||
tag_name="execute-command",
|
||||
tag_name="update-website-file",
|
||||
mappings=[
|
||||
{"param_name": "command", "node_type": "content", "path": "."},
|
||||
{"param_name": "file_path", "node_type": "attribute", "path": "@path"},
|
||||
{"param_name": "content", "node_type": "content", "path": "."},
|
||||
{"param_name": "create_dirs", "node_type": "attribute", "path": "@create_dirs"}
|
||||
],
|
||||
example='''
|
||||
<execute-command>
|
||||
npm install package-name
|
||||
</execute-command>
|
||||
<update-website-file path="index.html" create_dirs="true">
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>My Website</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
</body>
|
||||
</html>
|
||||
</update-website-file>
|
||||
'''
|
||||
)
|
||||
async def execute_command(self, command: str, folder: str = None) -> ToolResult:
|
||||
async def update_website_file(self, file_path: str, content: str, create_dirs: bool = True) -> ToolResult:
|
||||
print(f"\033[33mUpdating website file: {file_path}\033[0m")
|
||||
try:
|
||||
folder = folder or self.sandbox.get_user_root_dir()
|
||||
response = self.sandbox.process.exec(command, cwd=folder, timeout=60)
|
||||
|
||||
if response.exit_code == 0:
|
||||
return self.success_response({
|
||||
"output": response.result,
|
||||
"error": "",
|
||||
"exit_code": response.exit_code,
|
||||
"cwd": folder
|
||||
})
|
||||
else:
|
||||
return self.fail_response(f"Command failed with exit code {response.exit_code}: {response.result}")
|
||||
|
||||
site_dir = "/workspace/site"
|
||||
full_path = f"{site_dir}/{file_path}"
|
||||
|
||||
# Create the site directory if it doesn't exist
|
||||
self.sandbox.fs.create_folder(site_dir, "755")
|
||||
|
||||
# Create parent directories if needed
|
||||
if create_dirs and '/' in file_path:
|
||||
parent_dir = '/'.join(file_path.split('/')[:-1])
|
||||
if parent_dir:
|
||||
parent_path = f"{site_dir}/{parent_dir}"
|
||||
self.sandbox.fs.create_folder(parent_path, "755")
|
||||
|
||||
# Write the file content using the SDK
|
||||
self.sandbox.fs.upload_file(full_path, content.encode())
|
||||
|
||||
# Set appropriate permissions for web serving
|
||||
self.sandbox.fs.set_file_permissions(full_path, "644")
|
||||
|
||||
# Kill and restart the website server session
|
||||
self.sandbox.process.delete_session('sandbox_website_server')
|
||||
self.sandbox.process.create_session('sandbox_website_server')
|
||||
self.sandbox.process.execute_session_command('sandbox_website_server', SessionExecuteRequest(
|
||||
command="python " + self.sandbox.get_user_root_dir() + "/website_server.py",
|
||||
var_async=True
|
||||
))
|
||||
|
||||
return self.success_response({
|
||||
"message": f"File updated successfully at {file_path}",
|
||||
"path": file_path,
|
||||
"site_url": self.sandbox.get_preview_link(8080)
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
return self.fail_response(f"Error executing command: {str(e)}")
|
||||
return self.fail_response(f"Error updating website file: {str(e)}")
|
||||
|
|
|
@ -3,10 +3,13 @@ import requests
|
|||
from time import sleep
|
||||
|
||||
from daytona_sdk import Daytona, DaytonaConfig, CreateSandboxParams, SessionExecuteRequest
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from agentpress.tool import Tool
|
||||
from utils.logger import logger
|
||||
|
||||
load_dotenv()
|
||||
|
||||
config = DaytonaConfig(
|
||||
api_key=os.getenv("DAYTONA_API_KEY"),
|
||||
server_url=os.getenv("DAYTONA_SERVER_URL"),
|
||||
|
@ -15,7 +18,7 @@ config = DaytonaConfig(
|
|||
daytona = Daytona(config)
|
||||
|
||||
|
||||
sandbox_api = b'''
|
||||
sandbox_browser_api = b'''
|
||||
import traceback
|
||||
from fastapi import FastAPI, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
@ -145,6 +148,57 @@ if __name__ == "__main__":
|
|||
uvicorn.run(app, host="0.0.0.0", port=8000)
|
||||
'''
|
||||
|
||||
sandbox_website_server = b'''
|
||||
import os
|
||||
from fastapi import FastAPI, HTTPException, Request
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
import uvicorn
|
||||
import logging
|
||||
import logging.handlers
|
||||
|
||||
# Configure logging
|
||||
log_dir = "/var/log/kortix"
|
||||
os.makedirs(log_dir, exist_ok=True)
|
||||
log_file = os.path.join(log_dir, "website_server.log")
|
||||
|
||||
logger = logging.getLogger("website_server")
|
||||
logger.setLevel(logging.INFO)
|
||||
|
||||
# Create rotating file handler
|
||||
file_handler = logging.handlers.RotatingFileHandler(
|
||||
log_file,
|
||||
maxBytes=10485760, # 10MB
|
||||
backupCount=5
|
||||
)
|
||||
file_handler.setFormatter(
|
||||
logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||||
)
|
||||
logger.addHandler(file_handler)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
# Create site directory if it doesn't exist
|
||||
site_dir = "/workspace/site"
|
||||
os.makedirs(site_dir, exist_ok=True)
|
||||
|
||||
# Mount the static files directory
|
||||
app.mount("/", StaticFiles(directory=site_dir, html=True), name="site")
|
||||
|
||||
@app.get("/health")
|
||||
async def health_check():
|
||||
status = {
|
||||
"status": "healthy"
|
||||
}
|
||||
logger.debug(f"Health check: {status}")
|
||||
return status
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.info("Starting website server")
|
||||
uvicorn.run(app, host="0.0.0.0", port=8080)
|
||||
'''
|
||||
|
||||
|
||||
def create_sandbox(password: str):
|
||||
sandbox = daytona.create(CreateSandboxParams(
|
||||
image="adamcohenhillel/kortix-browser-use:0.0.1",
|
||||
|
@ -182,13 +236,18 @@ def create_sandbox(password: str):
|
|||
8080 # HTTP website port
|
||||
]
|
||||
))
|
||||
sandbox.fs.upload_file(sandbox.get_user_root_dir() + "/app.py", sandbox_api)
|
||||
sandbox.process.create_session('kortix_browser_use_api')
|
||||
rsp = sandbox.process.execute_session_command('kortix_browser_use_api', SessionExecuteRequest(
|
||||
command="python " + sandbox.get_user_root_dir() + "/app.py",
|
||||
sandbox.fs.upload_file(sandbox.get_user_root_dir() + "/browser_api.py", sandbox_browser_api)
|
||||
sandbox.fs.upload_file(sandbox.get_user_root_dir() + "/website_server.py", sandbox_website_server)
|
||||
sandbox.process.create_session('sandbox_browser_api')
|
||||
sandbox.process.create_session('sandbox_website_server')
|
||||
rsp = sandbox.process.execute_session_command('sandbox_browser_api', SessionExecuteRequest(
|
||||
command="python " + sandbox.get_user_root_dir() + "/browser_api.py",
|
||||
var_async=True
|
||||
))
|
||||
rsp2 = sandbox.process.execute_session_command('sandbox_website_server', SessionExecuteRequest(
|
||||
command="python " + sandbox.get_user_root_dir() + "/website_server.py",
|
||||
var_async=True
|
||||
))
|
||||
|
||||
times = 0
|
||||
success = False
|
||||
api_url = sandbox.get_preview_link(8000)
|
||||
|
@ -208,6 +267,7 @@ def create_sandbox(password: str):
|
|||
raise Exception("API call failed")
|
||||
|
||||
logger.info(f"Executed command {rsp}")
|
||||
logger.info(f"Executed command {rsp2}")
|
||||
logger.info(f"Created kortix_browser_use_api session `kortix_browser_use_api`")
|
||||
return sandbox
|
||||
|
||||
|
@ -231,5 +291,5 @@ class SandboxToolsBase(Tool):
|
|||
|
||||
print("\033[95m***")
|
||||
print(self.sandbox.get_preview_link(6080))
|
||||
print("***\033[0m")
|
||||
|
||||
print(self.sandbox.get_preview_link(8080))
|
||||
print("***\033[0m")
|
Loading…
Reference in New Issue