diff --git a/backend/agent/prompt.py b/backend/agent/prompt.py index d2c15cd2..01683673 100644 --- a/backend/agent/prompt.py +++ b/backend/agent/prompt.py @@ -103,6 +103,7 @@ You have the ability to execute operations using both Python and CLI tools: - WEBSITE DEPLOYMENT: * Only use the 'deploy' tool when users explicitly request permanent deployment to a production environment * The deploy tool publishes static HTML+CSS+JS sites to a public URL using Cloudflare Pages + * If the same name is used for deployment, it will redeploy to the same project as before * For temporary or development purposes, serve files locally instead of using the deployment tool * Always confirm with the user before deploying to production - ask if permanent deployment is needed * When deploying, ensure all assets (images, scripts, stylesheets) use relative paths to work correctly diff --git a/backend/agent/run.py b/backend/agent/run.py index 6b7a1e18..76736d9c 100644 --- a/backend/agent/run.py +++ b/backend/agent/run.py @@ -36,7 +36,7 @@ async def run_agent(thread_id: str, project_id: str, stream: bool = True, thread 'sandbox_id': sandbox_id, 'sandbox_pass': sandbox_pass }).eq('project_id', project_id).execute() - # thread_manager.add_tool(SandboxBrowseTool, sandbox_id=sandbox_id, password=sandbox_pass) + thread_manager.add_tool(SandboxShellTool, sandbox_id=sandbox_id, password=sandbox_pass) thread_manager.add_tool(SandboxFilesTool, sandbox_id=sandbox_id, password=sandbox_pass) thread_manager.add_tool(WebSearchTool) diff --git a/backend/agent/tools/message_tool.py b/backend/agent/tools/message_tool.py index 7f8850c6..e8599107 100644 --- a/backend/agent/tools/message_tool.py +++ b/backend/agent/tools/message_tool.py @@ -77,7 +77,7 @@ class MessageTool(Tool): if attachments and isinstance(attachments, str): attachments = [attachments] - return self.success_response({"status": "success"}) + return self.success_response({"status": "Awaiting user response..."}) except Exception as e: return self.fail_response(f"Error asking user: {str(e)}") diff --git a/backend/agent/tools/sb_deploy_tool.py b/backend/agent/tools/sb_deploy_tool.py index 3be645de..0fb924d9 100644 --- a/backend/agent/tools/sb_deploy_tool.py +++ b/backend/agent/tools/sb_deploy_tool.py @@ -3,6 +3,7 @@ from dotenv import load_dotenv from agentpress.tool import ToolResult, openapi_schema, xml_schema from sandbox.sandbox import SandboxToolsBase from utils.files_utils import clean_path +from agent.tools.sb_shell_tool import SandboxShellTool # Load environment variables load_dotenv() @@ -14,6 +15,7 @@ class SandboxDeployTool(SandboxToolsBase): super().__init__(sandbox_id, password) self.workspace_path = "/workspace" # Ensure we're always operating in /workspace self.cloudflare_api_token = os.getenv("CLOUDFLARE_API_TOKEN") + self.shell_tool = SandboxShellTool(sandbox_id, password) def clean_path(self, path: str) -> str: """Clean and normalize a path to be relative to /workspace""" @@ -43,14 +45,16 @@ class SandboxDeployTool(SandboxToolsBase): @xml_schema( tag_name="deploy", mappings=[ - {"param_name": "name", "node_type": "attribute", "path": "."}, - {"param_name": "directory_path", "node_type": "attribute", "path": "."} + {"param_name": "name", "node_type": "attribute", "path": "name"}, + {"param_name": "directory_path", "node_type": "attribute", "path": "directory_path"} ], example=''' @@ -89,36 +93,52 @@ class SandboxDeployTool(SandboxToolsBase): if not self.cloudflare_api_token: return self.fail_response("CLOUDFLARE_API_TOKEN environment variable not set") - # Build the deployment command with authentication included - deploy_cmd = ( - f"export CLOUDFLARE_API_TOKEN='{self.cloudflare_api_token}' && " - # Verify authentication first - f"npx wrangler whoami > /dev/null && " - # Then deploy - f"npx wrangler pages deploy {full_path} " - f"--project-name {name} " - f"--branch main " - f"--commit-dirty=true" + # Single command that creates the project if it doesn't exist and then deploys + project_name = f"{self.sandbox_id}-{name}" + deploy_cmd = f'''export CLOUDFLARE_API_TOKEN={self.cloudflare_api_token} && + (npx wrangler pages deploy {full_path} --project-name {project_name} || + (npx wrangler pages project create {project_name} --production-branch production && + npx wrangler pages deploy {full_path} --project-name {project_name}))''' + + # Execute command using shell_tool.execute_command + response = await self.shell_tool.execute_command( + command=deploy_cmd, + folder=None, # Use the workspace root + timeout=300 # Increased timeout for deployments ) - # Execute command directly using process.exec - response = self.sandbox.process.exec(deploy_cmd, cwd=self.workspace_path) + print(f"Deployment response: {response}") - if response.exit_code == 0: + if response.success: return self.success_response({ "message": f"Website deployed successfully", - "url": f"https://{name}.kortix.cloud", - "details": { - "output": response.stdout, - "project_name": name, - "url": f"https://{name}.kortix.cloud" - } + "output": response.output }) else: - return self.fail_response(f"Deployment failed: {response.stderr or 'Deployment failed with no error message'}") + return self.fail_response(f"Deployment failed: {response.output}") except Exception as e: return self.fail_response(f"Error during deployment: {str(e)}") - except Exception as e: return self.fail_response(f"Error deploying website: {str(e)}") +if __name__ == "__main__": + import asyncio + import sys + + async def test_deploy(): + # Replace these with actual values for testing + sandbox_id = "sandbox-ccb30b35" + password = "test-password" + + # Initialize the deploy tool + deploy_tool = SandboxDeployTool(sandbox_id, password) + + # Test deployment - replace with actual directory path and site name + result = await deploy_tool.deploy( + name="test-site-1x", + directory_path="website" # Directory containing static site files + ) + print(f"Deployment result: {result}") + + asyncio.run(test_deploy()) + diff --git a/backend/utils/logger.py b/backend/utils/logger.py index acb4bbe8..6d2abc39 100644 --- a/backend/utils/logger.py +++ b/backend/utils/logger.py @@ -64,7 +64,7 @@ def setup_logger(name: str = 'agentpress') -> logging.Logger: logging.Logger: Configured logger instance """ logger = logging.getLogger(name) - logger.setLevel(logging.DEBUG) + logger.setLevel(logging.INFO) # Create logs directory if it doesn't exist log_dir = 'logs'