feat(koyeb): add Koyeb backend support for cloud execution and environment management

This commit is contained in:
Fabzerito 2026-04-22 23:00:03 +02:00
parent 57e33cf284
commit abd5eacb6e
11 changed files with 479 additions and 64 deletions

View file

@ -437,7 +437,8 @@ DEFAULT_CONFIG = {
"singularity_image": "docker://nikolaik/python-nodejs:python3.11-nodejs20",
"modal_image": "nikolaik/python-nodejs:python3.11-nodejs20",
"daytona_image": "nikolaik/python-nodejs:python3.11-nodejs20",
# Container resource limits (docker, singularity, modal, daytona — ignored for local/ssh)
"koyeb_image": "koyeb/sandbox:latest",
# Container resource limits (docker, singularity, modal, daytona, koyeb — ignored for local/ssh)
"container_cpu": 1,
"container_memory": 5120, # MB (default 5GB)
"container_disk": 51200, # MB (default 50GB)
@ -3694,6 +3695,10 @@ def show_config():
print(f" Daytona image: {terminal.get('daytona_image', 'nikolaik/python-nodejs:python3.11-nodejs20')}")
daytona_key = get_env_value('DAYTONA_API_KEY')
print(f" API key: {'configured' if daytona_key else '(not set)'}")
elif terminal.get('backend') == 'koyeb':
print(f" Koyeb image: {terminal.get('koyeb_image', 'koyeb/sandbox:latest')}")
koyeb_token = get_env_value('KOYEB_API_TOKEN')
print(f" API token: {'configured' if koyeb_token else '(not set)'}")
elif terminal.get('backend') == 'ssh':
ssh_host = get_env_value('TERMINAL_SSH_HOST')
ssh_user = get_env_value('TERMINAL_SSH_USER')
@ -3886,6 +3891,7 @@ def set_config_value(key: str, value: str):
"terminal.singularity_image": "TERMINAL_SINGULARITY_IMAGE",
"terminal.modal_image": "TERMINAL_MODAL_IMAGE",
"terminal.daytona_image": "TERMINAL_DAYTONA_IMAGE",
"terminal.koyeb_image": "TERMINAL_KOYEB_IMAGE",
"terminal.docker_mount_cwd_to_workspace": "TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACE",
"terminal.cwd": "TERMINAL_CWD",
"terminal.timeout": "TERMINAL_TIMEOUT",

View file

@ -777,6 +777,21 @@ def run_doctor(args):
check_fail("daytona SDK not installed", "(pip install daytona)")
issues.append("Install daytona SDK: pip install daytona")
# Koyeb (if using koyeb backend)
if terminal_env == "koyeb":
koyeb_token = os.getenv("KOYEB_API_TOKEN")
if koyeb_token:
check_ok("Koyeb API token", "(configured)")
else:
check_fail("KOYEB_API_TOKEN not set", "(required for TERMINAL_ENV=koyeb)")
issues.append("Set KOYEB_API_TOKEN environment variable")
try:
from koyeb import Sandbox # noqa: F401 — SDK presence check
check_ok("koyeb SDK", "(installed)")
except ImportError:
check_fail("koyeb SDK not installed", "(pip install koyeb-sdk)")
issues.append("Install koyeb SDK: pip install koyeb-sdk")
# Node.js + agent-browser (for browser automation tools)
if shutil.which("node"):
check_ok("Node.js")

View file

@ -1182,11 +1182,12 @@ def setup_terminal_backend(config: dict):
"Modal - serverless cloud sandbox",
"SSH - run on a remote machine",
"Daytona - persistent cloud development environment",
"Koyeb - cloud sandbox execution",
]
idx_to_backend = {0: "local", 1: "docker", 2: "modal", 3: "ssh", 4: "daytona"}
backend_to_idx = {"local": 0, "docker": 1, "modal": 2, "ssh": 3, "daytona": 4}
idx_to_backend = {0: "local", 1: "docker", 2: "modal", 3: "ssh", 4: "daytona", 5: "koyeb"}
backend_to_idx = {"local": 0, "docker": 1, "modal": 2, "ssh": 3, "daytona": 4, "koyeb": 5}
next_idx = 5
next_idx = 6
if is_linux:
terminal_choices.append("Singularity/Apptainer - HPC-friendly container")
idx_to_backend[next_idx] = "singularity"
@ -1441,6 +1442,64 @@ def setup_terminal_backend(config: dict):
_prompt_container_resources(config)
elif selected_backend == "koyeb":
print_success("Terminal backend: Koyeb")
print_info("Cloud sandbox execution via Koyeb.")
print_info("Sign up at: https://www.koyeb.com")
# Check if koyeb SDK is installed
try:
__import__("koyeb")
except ImportError:
print_info("Installing koyeb SDK...")
import subprocess
uv_bin = shutil.which("uv")
if uv_bin:
result = subprocess.run(
[uv_bin, "pip", "install", "--python", sys.executable, "koyeb-sdk"],
capture_output=True,
text=True,
)
else:
result = subprocess.run(
[sys.executable, "-m", "pip", "install", "koyeb-sdk"],
capture_output=True,
text=True,
)
if result.returncode == 0:
print_success("koyeb SDK installed")
else:
print_warning("Install failed — run manually: pip install koyeb-sdk")
if result.stderr:
print_info(f" Error: {result.stderr.strip().splitlines()[-1]}")
# Koyeb API token
print()
existing_key = get_env_value("KOYEB_API_TOKEN")
if existing_key:
print_info(" Koyeb API token: already configured")
if prompt_yes_no(" Update API token?", False):
api_key = prompt(" Koyeb API token", password=True)
if api_key:
save_env_value("KOYEB_API_TOKEN", api_key)
print_success(" Updated")
else:
api_key = prompt(" Koyeb API token", password=True)
if api_key:
save_env_value("KOYEB_API_TOKEN", api_key)
print_success(" Configured")
# Koyeb image
current_image = config.get("terminal", {}).get(
"koyeb_image", "koyeb/sandbox:latest"
)
image = prompt(" Sandbox image", current_image)
config["terminal"]["koyeb_image"] = image
save_env_value("TERMINAL_KOYEB_IMAGE", image)
_prompt_container_resources(config)
elif selected_backend == "ssh":
print_success("Terminal backend: SSH")
print_info("Run commands on a remote machine via SSH.")