From 942386331943e4eb890ff83fbfe9ebcbedc8e8e6 Mon Sep 17 00:00:00 2001 From: Dillon DuPont Date: Wed, 1 Oct 2025 16:57:15 -0400 Subject: [PATCH 1/3] add windows cloud example --- examples/computer_examples_windows.py | 84 +++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 examples/computer_examples_windows.py diff --git a/examples/computer_examples_windows.py b/examples/computer_examples_windows.py new file mode 100644 index 00000000..2efefce4 --- /dev/null +++ b/examples/computer_examples_windows.py @@ -0,0 +1,84 @@ +import os +import asyncio +from pathlib import Path +import sys +import traceback + +# Load environment variables from .env file +project_root = Path(__file__).parent.parent +env_file = project_root / ".env" +print(f"Loading environment from: {env_file}") +from dotenv import load_dotenv + +load_dotenv(env_file) + +# Add paths to sys.path if needed +pythonpath = os.environ.get("PYTHONPATH", "") +for path in pythonpath.split(":"): + if path and path not in sys.path: + sys.path.insert(0, path) # Insert at beginning to prioritize + print(f"Added to sys.path: {path}") + +from computer.computer import Computer +from computer.providers.base import VMProviderType +from computer.logger import LogLevel + +async def main(): + try: + print("\n=== Using direct initialization ===") + + # Create a remote Windows computer with Cua + computer = Computer( + os_type="windows", + api_key=os.getenv("CUA_API_KEY"), + name=os.getenv("CONTAINER_NAME") or "", + provider_type=VMProviderType.CLOUD, + ) + + try: + # Run the computer with default parameters + await computer.run() + + screenshot = await computer.interface.screenshot() + + # Create output directory if it doesn't exist + output_dir = Path("./output") + output_dir.mkdir(exist_ok=True) + + # Mouse Actions Examples + print("\n=== Mouse Actions ===") + await computer.interface.move_cursor(100, 100) + await computer.interface.left_click() + await computer.interface.double_click(400, 400) + await computer.interface.right_click(300, 300) + + # Command Actions Examples + print("\n=== Command Actions ===") + await computer.interface.run_command("notepad") + + screenshot_path = output_dir / "screenshot.png" + with open(screenshot_path, "wb") as f: + f.write(screenshot) + print(f"Screenshot saved to: {screenshot_path.absolute()}") + + # Keyboard Actions Examples + print("\n=== Keyboard Actions ===") + await computer.interface.type_text("Hello, World!") + await computer.interface.press_key("enter") + + # Clipboard Actions Examples + print("\n=== Clipboard Actions ===") + await computer.interface.set_clipboard("Test clipboard") + content = await computer.interface.copy_to_clipboard() + print(f"Clipboard content: {content}") + + finally: + # Important to clean up resources + await computer.stop() + except Exception as e: + print(f"Error in main: {e}") + traceback.print_exc() + + +if __name__ == "__main__": + asyncio.run(main()) From 83cad3b68777e7a0c40d7bbecd4ccc7f34d28346 Mon Sep 17 00:00:00 2001 From: Dillon DuPont Date: Fri, 3 Oct 2025 10:41:21 -0400 Subject: [PATCH 2/3] Disable stop windows --- examples/computer_examples_windows.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/computer_examples_windows.py b/examples/computer_examples_windows.py index 2efefce4..4182026e 100644 --- a/examples/computer_examples_windows.py +++ b/examples/computer_examples_windows.py @@ -31,7 +31,7 @@ async def main(): computer = Computer( os_type="windows", api_key=os.getenv("CUA_API_KEY"), - name=os.getenv("CONTAINER_NAME") or "", + name="s-windows-x4snp46ebf", # os.getenv("CONTAINER_NAME") or "", provider_type=VMProviderType.CLOUD, ) @@ -74,7 +74,8 @@ async def main(): finally: # Important to clean up resources - await computer.stop() + # await computer.stop() + pass except Exception as e: print(f"Error in main: {e}") traceback.print_exc() From 1cacd281ad0cb50019076165f43ab0ac5434e6be Mon Sep 17 00:00:00 2001 From: Dillon DuPont Date: Fri, 3 Oct 2025 12:12:40 -0400 Subject: [PATCH 3/3] fixed python RPC on windows --- examples/computer_examples_windows.py | 77 ++++++++++++++++++++--- libs/python/computer/computer/computer.py | 76 ++++++++++++++-------- 2 files changed, 119 insertions(+), 34 deletions(-) diff --git a/examples/computer_examples_windows.py b/examples/computer_examples_windows.py index 4182026e..22c08416 100644 --- a/examples/computer_examples_windows.py +++ b/examples/computer_examples_windows.py @@ -8,6 +8,7 @@ import traceback project_root = Path(__file__).parent.parent env_file = project_root / ".env" print(f"Loading environment from: {env_file}") +from computer.helpers import sandboxed from dotenv import load_dotenv load_dotenv(env_file) @@ -23,6 +24,10 @@ from computer.computer import Computer from computer.providers.base import VMProviderType from computer.logger import LogLevel +# ANSI color codes +RED = '\033[91m' +RESET = '\033[0m' + async def main(): try: print("\n=== Using direct initialization ===") @@ -39,12 +44,15 @@ async def main(): # Run the computer with default parameters await computer.run() - screenshot = await computer.interface.screenshot() - # Create output directory if it doesn't exist output_dir = Path("./output") output_dir.mkdir(exist_ok=True) + # Keyboard Actions Examples + print("\n=== Keyboard Actions ===") + await computer.interface.type_text("Hello, World!") + await computer.interface.press_key("enter") + # Mouse Actions Examples print("\n=== Mouse Actions ===") await computer.interface.move_cursor(100, 100) @@ -52,26 +60,77 @@ async def main(): await computer.interface.double_click(400, 400) await computer.interface.right_click(300, 300) + print("\n=== RPC ===") + await computer.venv_install("demo_venv", ["mss"]) + + @sandboxed("demo_venv") + def greet_and_print(name): + from mss import mss + import os + # get username + username = os.getlogin() + print(f"Hello from inside the container, {name}!") + print("Username:", username) + print("Screens:", mss().monitors) + + # take a screenshot + with mss() as sct: + filename = sct.shot(mon=-1, output='C:/Users/azureuser/Desktop/fullscreen.png') + print(filename) + + return {"greeted": name, "username": username} + + # Call with args and kwargs + result = await greet_and_print("John Doe") + print("Result from sandboxed function:", result) + # Command Actions Examples print("\n=== Command Actions ===") - await computer.interface.run_command("notepad") + result = await computer.interface.run_command("notepad") + print("Result from command:", result) + screenshot = await computer.interface.screenshot() screenshot_path = output_dir / "screenshot.png" with open(screenshot_path, "wb") as f: f.write(screenshot) print(f"Screenshot saved to: {screenshot_path.absolute()}") - # Keyboard Actions Examples - print("\n=== Keyboard Actions ===") - await computer.interface.type_text("Hello, World!") - await computer.interface.press_key("enter") - # Clipboard Actions Examples print("\n=== Clipboard Actions ===") await computer.interface.set_clipboard("Test clipboard") content = await computer.interface.copy_to_clipboard() print(f"Clipboard content: {content}") + + # Simple REPL Loop + print("\n=== Command REPL ===") + print("Enter commands to run on the remote computer.") + print("Type 'exit' or 'quit' to leave the REPL.\n") + + while True: + try: + # Get command from user + command = input("command> ").strip() + + # Check for exit commands + if command.lower() in ['exit', 'quit', '']: + if command.lower() in ['exit', 'quit']: + print("Exiting REPL...") + break + + # Run the command + result = await computer.interface.run_command(command) + + print(result.stdout) + if result.stderr: + print(f"{RED}{result.stderr}{RESET}") + except KeyboardInterrupt: + print("\nExiting REPL...") + break + except Exception as e: + print(f"{RED}Error running command: {e}{RESET}") + + finally: # Important to clean up resources # await computer.stop() @@ -82,4 +141,4 @@ async def main(): if __name__ == "__main__": - asyncio.run(main()) + asyncio.run(main()) \ No newline at end of file diff --git a/libs/python/computer/computer/computer.py b/libs/python/computer/computer/computer.py index f01c5491..6841f2f2 100644 --- a/libs/python/computer/computer/computer.py +++ b/libs/python/computer/computer/computer.py @@ -794,19 +794,33 @@ class Computer: Tuple of (stdout, stderr) from the installation command """ requirements = requirements or [] - - # Create virtual environment if it doesn't exist - venv_path = f"~/.venvs/{venv_name}" - create_cmd = f"mkdir -p ~/.venvs && python3 -m venv {venv_path}" - - # Check if venv exists, if not create it - check_cmd = f"test -d {venv_path} || ({create_cmd})" - _ = await self.interface.run_command(check_cmd) - - # Install packages - requirements_str = " ".join(requirements) - install_cmd = f". {venv_path}/bin/activate && pip install {requirements_str}" - return await self.interface.run_command(install_cmd) + # Windows vs POSIX handling + if self.os_type == "windows": + # Use %USERPROFILE% for home directory and cmd.exe semantics + venv_path = f"%USERPROFILE%\\.venvs\\{venv_name}" + ensure_dir_cmd = "if not exist \"%USERPROFILE%\\.venvs\" mkdir \"%USERPROFILE%\\.venvs\"" + create_cmd = f"if not exist \"{venv_path}\" python -m venv \"{venv_path}\"" + requirements_str = " ".join(requirements) + # Activate via activate.bat and install + install_cmd = f"call \"{venv_path}\\Scripts\\activate.bat\" && pip install {requirements_str}" if requirements_str else f"echo No requirements to install" + await self.interface.run_command(ensure_dir_cmd) + await self.interface.run_command(create_cmd) + return await self.interface.run_command(install_cmd) + else: + # POSIX (macOS/Linux) + venv_path = f"$HOME/.venvs/{venv_name}" + create_cmd = f"mkdir -p \"$HOME/.venvs\" && python3 -m venv \"{venv_path}\"" + # Check if venv exists, if not create it + check_cmd = f"test -d \"{venv_path}\" || ({create_cmd})" + _ = await self.interface.run_command(check_cmd) + # Install packages + requirements_str = " ".join(requirements) + install_cmd = ( + f". \"{venv_path}/bin/activate\" && pip install {requirements_str}" + if requirements_str + else "echo No requirements to install" + ) + return await self.interface.run_command(install_cmd) async def venv_cmd(self, venv_name: str, command: str): """Execute a shell command in a virtual environment. @@ -818,18 +832,30 @@ class Computer: Returns: Tuple of (stdout, stderr) from the command execution """ - venv_path = f"~/.venvs/{venv_name}" - - # Check if virtual environment exists - check_cmd = f"test -d {venv_path}" - result = await self.interface.run_command(check_cmd) - - if result.stderr or "test:" in result.stdout: # venv doesn't exist - return "", f"Virtual environment '{venv_name}' does not exist. Create it first using venv_install." - - # Activate virtual environment and run command - full_command = f". {venv_path}/bin/activate && {command}" - return await self.interface.run_command(full_command) + if self.os_type == "windows": + # Windows (cmd.exe) + venv_path = f"%USERPROFILE%\\.venvs\\{venv_name}" + # Check existence and signal if missing + check_cmd = f"if not exist \"{venv_path}\" (echo VENV_NOT_FOUND) else (echo VENV_FOUND)" + result = await self.interface.run_command(check_cmd) + if "VENV_NOT_FOUND" in getattr(result, "stdout", ""): + # Auto-create the venv with no requirements + await self.venv_install(venv_name, []) + # Activate and run the command + full_command = f"call \"{venv_path}\\Scripts\\activate.bat\" && {command}" + return await self.interface.run_command(full_command) + else: + # POSIX (macOS/Linux) + venv_path = f"$HOME/.venvs/{venv_name}" + # Check if virtual environment exists + check_cmd = f"test -d \"{venv_path}\"" + result = await self.interface.run_command(check_cmd) + if result.stderr or "test:" in result.stdout: # venv doesn't exist + # Auto-create the venv with no requirements + await self.venv_install(venv_name, []) + # Activate virtual environment and run command + full_command = f". \"{venv_path}/bin/activate\" && {command}" + return await self.interface.run_command(full_command) async def venv_exec(self, venv_name: str, python_func, *args, **kwargs): """Execute Python function in a virtual environment using source code extraction.