diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x.json b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x.json new file mode 100644 index 000000000..771796533 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x.json @@ -0,0 +1,34 @@ +{ + "version.label": { + "message": "1.1.x", + "description": "The label for version 1.1.x" + }, + "sidebar.tutorialSidebar.category.Getting Started": { + "message": "快速上手", + "description": "The label for category 'Getting Started' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.User Guides": { + "message": "用户指南", + "description": "The label for category 'User Guides' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.References": { + "message": "参考", + "description": "The label for category 'References' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.Release Notes": { + "message": "版本说明", + "description": "The label for category 'Release Notes' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.model-service": { + "message": "Model Service 参考", + "description": "The label for category 'Model Service References' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.sandbox-agent": { + "message": "Sandbox Agent参考", + "description": "The label for category 'Sandbox Agent References' in sidebar 'tutorialSidebar'" + }, + "sidebar.tutorialSidebar.category.Python SDK References": { + "message": "Python SDK 参考", + "description": "The label for category 'Python SDK References' in sidebar 'tutorialSidebar'" + } +} \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/installation.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/installation.md new file mode 100644 index 000000000..0ab70e55d --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/installation.md @@ -0,0 +1,141 @@ +--- +sidebar_position: 3 +--- + +# 安装指南 + +本文档介绍如何使用 `uv` 和 `pip` 安装和设置 ROCK 开发环境。该项目是一个强化学习开放构建工具包,支持多种组件。 + +## 使用 uv(推荐) + +### 快速安装所有依赖 + +```bash +# 安装所有依赖(包括可选依赖) +uv sync --all-extras + +# 安装开发/测试依赖 +uv sync --all-extras --all-groups +``` + +### 安装不同依赖组 + +#### 仅核心依赖 +```bash +uv sync +``` + +#### 管理组件依赖 +```bash +uv sync --extra admin +``` + +#### Rocklet 执行环境依赖 +```bash +uv sync --extra rocklet +``` + +#### 所有依赖 +```bash +uv sync --all-extras +``` + +#### 开发/测试依赖 +```bash +uv sync --all-extras --group test +``` + +## 使用 pip + +### 从 pip 源安装 + +#### 仅核心依赖 +```bash +pip install rl-rock +``` + +#### 管理组件依赖 +```bash +pip install "rl-rock[admin]" +``` + +#### Rocklet 执行环境依赖 +```bash +pip install "rl-rock[rocklet]" +``` + +#### 构建器依赖 +```bash +pip install "rl-rock[builder]" +``` + +#### 安装所有可选依赖 +```bash +pip install "rl-rock[all]" +``` + +### 使用 pip 从源码安装 + +#### 仅核心依赖 +```bash +pip install . +``` + +#### 管理组件依赖 +```bash +pip install ".[admin]" +``` + +#### Rocklet 执行环境依赖 +```bash +pip install ".[rocklet]" +``` + +#### 构建器依赖 +```bash +pip install ".[builder]" +``` + +#### 安装所有可选依赖 +```bash +pip install ".[all]" +``` + +## 可用入口点 + +该包提供以下命令行脚本: + +- `rocklet`: ROCK 执行环境服务器 (rock.rocklet.server:main) +- `admin`: 管理服务器 (rock.admin.main:main) +- `envhub`: 环境中心服务器 (rock.envhub.server:main) +- `rock`: 主 ROCK 命令行接口 (rock.cli.main:main) + +## 开发设置 + +### 使用 uv(推荐) + +```bash +# 克隆并设置开发环境 +git clone +cd ROCK +uv sync --all-extras --group test + +# 运行测试 +uv run pytest + + +### 使用 pip + +```bash +# 开发模式安装所有可选依赖 +pip install -e ".[all]" + +# 分别安装 +pip install -e . +pip install ".[admin]" ".[rocklet]" ".[builder]" +``` + +## 附加说明 + +- 项目配置为默认使用阿里云 PyPI 镜像: `https://mirrors.aliyun.com/pypi/simple/` +- 对于本地开发,运行测试需要 `test` 依赖组 diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/quickstart.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/quickstart.md new file mode 100644 index 000000000..e0a0891c0 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/quickstart.md @@ -0,0 +1,172 @@ +--- +sidebar_position: 2 +--- + +# 快速上手 + +本指南将通过完整的示例演示如何使用 ROCK 创建和管理强化学习环境。ROCK (Reinforcement Open Construction Kit) 是一个全面的沙箱环境管理框架,主要用于强化学习和AI开发环境。 + +## 1. 环境准备 + +我们推荐在 Linux 系统下启动 ROCK,能够尽量复用项目依赖,提升环境拉起速度。如果需要在 macOS 上尝试,可以参考 [MacOS 启动](#7-macos-启动) 一节。 + +在开始之前,请确保您的系统已安装以下依赖项: + +### 1.1 系统要求 + +- **Docker**: ROCK 使用 Docker 进行容器化环境管理 +- **uv**: ROCK 使用 uv 进行依赖管理和虚拟环境创建 + +### 1.2 验证依赖安装 + +```bash +# 验证 Docker 安装 +docker --version + +# 验证 Docker 可用, 且示例中依赖python:3.11镜像 +docker pull python:3.11 + +# 验证 uv 安装 +uv --version + + +``` + +### 1.3 项目初始化 + +```bash +# 克隆项目仓库 +git clone +cd ROCK + +# 创建虚拟环境(使用 uv 托管的 Python, 以python 3.11 版本为例) +uv venv --python 3.11 --python-preference only-managed + +# 安装所有依赖组 +uv sync --all-extras +``` + +> **重要提示**: 为确保 ROCK 能正确挂载项目和虚拟环境及其依赖的 base Python 解释器,强烈推荐使用 uv 托管的 Python 环境而非系统 Python。 + +## 2. 激活虚拟环境 + +在运行任何 ROCK 命令之前,需要先激活虚拟环境。确保 sys.base_prefix 是 uv 管理的环境,类似于 `/root/.local/share/uv/python/cpython-3.11.8-linux-x86_64-gnu` 等路径。 + +```bash +# 激活虚拟环境 +source .venv/bin/activate + +# 验证 Python 环境 +python -c "import sys; print('Base prefix:', sys.base_prefix)" +``` + +> **验证要点**: 确保输出的 base prefix 路径指向 uv 管理的 Python 环境,而非系统 Python。 + +## 3. 验证环境配置 + +激活虚拟环境后,验证依赖安装是否正确: + +```bash +# 检查关键依赖 +python -c "import rock; print(\"Hello ROCK\")" +``` + + +## 4. 启动 ROCK 服务 + +激活虚拟环境后,在项目根目录下,启动 ROCK Admin 服务: + +```bash +# 确保虚拟环境已激活 +source .venv/bin/activate + +# 启动 ROCK Admin 服务(本地环境) +rock admin start +``` + +服务启动后,您将看到类似以下的输出: + +``` +INFO: Started server process [12345] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit) +``` + +> **服务说明**: ROCK Admin 服务默认运行在 `http://127.0.0.1:8080`。 + +## 5. 运行示例环境 + +现在可以运行示例环境来验证安装。确保 ROCK 服务正在运行,然后打开一个新的终端窗口执行以下命令: + +```bash +# 确保虚拟环境已激活 +source .venv/bin/activate + +# 运行沙箱示例 +python examples/sandbox_demo.py + +# 运行 GEM 协议示例 +python examples/sokoban_demo.py +``` + +### 5.1 示例说明 + +- **sandbox_demo.py**: 演示如何使用 ROCK 的沙箱 SDK 创建和管理容器化环境 +- **sokoban_demo.py**: 演示如何使用 ROCK 的 GEM 协议兼容接口创建强化学习环境 + +> **运行要求**: 确保 ROCK Admin 服务正在运行,因为示例需要与服务进行通信。 + +## 6. 分布式环境配置(可选) + +对于分布式多机器环境,请确保以下配置一致: + +1. 所有机器上 ROCK 和 uv 的 Python 配置使用相同的根 Python 解释器 +2. Docker 版本在所有节点上保持一致 +3. 网络配置允许各节点间正常通信 + + + +## 7. MacOS 启动 + +在 macOS 上,如果需要启动 Linux 镜像的环境,需要先设置环境变量: + +```bash +export ROCK_WORKER_ENV_TYPE=uv +``` + +在容器启动时,会安装对应的 uv 环境,细节可以参考 `rock/rocklet/local_files/docker_run_with_uv.sh` 脚本。 + +> **注意**: 相比 Linux 系统,macOS 上的启动速度会较慢,且比较依赖网络环境,可以根据实际情况调整脚本。ROCK_WORKER_ENV_TYPE的细节可以参考 [Configuration Guide](../User%20Guides/configuration.md). + + +## 8. 从Pip源启动 + +如果从Pip源启动Admin Server,在参照[安装指南](./installation.md)安装完成ROCK后, 需要设置额外环境变量: + +```bash +export ROCK_WORKER_ENV_TYPE=pip +``` + +(这一启动方式在容器环境启动时会从Pypi源上拉取最新的rocklet并安装, 相对启动速度比较慢, 仅推荐测试使用, 生产上依旧推荐其他的启动方式) + + +## 总结 + +恭喜!您已经成功完成了 ROCK 的快速开始指南。现在您应该能够: + +- 正确设置 ROCK 开发环境 +- 使用 uv 管理的 Python 环境 +- 启动和管理 ROCK 服务 +- 运行示例程序验证安装 +- 在分布式环境中配置 ROCK(如果需要) + +如需深入了解 ROCK 的更多功能,请参考以下文档: + +## 下一步学习 + +- [配置指南](../User%20Guides/configuration.md) - 详细了解 ROCK 的配置选项 +- [API 文档](../References/api.md) - 查看完整的 API 接口 +- [Python SDK 文档](../References/Python%20SDK%20References/python_sdk.md) - 学习如何使用 Python SDK 进行开发 +- [安装指南](./installation.md) - 详细了解 ROCK 安装和配置 +- [概览](../overview.md) - 了解 ROCK 的设计理念 \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/rockroll.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/rockroll.md new file mode 100644 index 000000000..3b53810ba --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Getting Started/rockroll.md @@ -0,0 +1,200 @@ +--- +sidebar_position: 7 +--- + +# ROCK & ROLL 快速开始指南 + +本指南将引导您使用 ROLL (训练框架) 和 ROCK (环境管理) 来运行一个基于 Sokoban 游戏(推箱子)的强化学习训练示例。 + +## 1. 单机环境准备 + +在开始之前,请先确保您的系统已安装以下依赖项: + +### 1.1 系统要求 + +- **操作系统**: 推荐使用 Linux (如 Ubuntu 20.04+) +- **硬件**: 建议使用 NVIDIA GPU 并安装对应的驱动程序 +- **Docker**: ROCK 使用 Docker 进行容器化环境管理 +- **uv**: ROCK 使用 uv 进行依赖管理和虚拟环境创建 + +### 1.2 验证依赖安装 + +```bash +# 验证 Docker 安装 +docker --version + +# 验证 Docker 可用, 且可提前拉取 Sokoban 游戏环境镜像,避免训练时等待 +docker pull rock-n-roll-registry.cn-hangzhou.cr.aliyuncs.com/rock/sokoban-sandbox:latest + +# 验证 uv 安装 +uv --version + +``` + +### 1.3 项目初始化 + +```bash +# 克隆项目仓库 +git clone https://github.com/alibaba/ROCK.git +git clone https://github.com/alibaba/ROLL.git + +# 确保两个仓库位于同一级目录下,如下所示: +# your-workspace/ +# ├── ROCK/ +# └── ROLL/ +``` + + +## 2. 启动训练流程 + +> 说明:下文均以 *torch2.6.0 + vLLM0.8.4* 为例。 + + +### 方式一: 使用虚拟环境启动(推荐) + +#### 为什么推荐这种方式? +- 隔离性:uv 虚拟环境能确保项目依赖与系统环境隔离,避免冲突。 +- 速度快:ROCK 可以复用此虚拟环境,大大加快了后续环境的启动速度。 +- 稳定性:依赖关系更清晰,环境更易复现。 + + +```bash +# 进入 ROCK 目录 +cd ROCK + +# 使用 uv 创建并激活 Python 3.10 虚拟环境(ROLL推荐使用Python 3.10) +uv venv --python 3.10 --python-preference only-managed + +# 激活虚拟环境 +source .venv/bin/activate + +# 使用uv安装ROCK的依赖 +uv sync --all-extras + +# 若使用Python 3.10, 启动 ray 时会报错:ValueError: is not a valid Sentinel +# 原因是 ray 与 click>=8.3 版本不兼容,需要降级到 click<8.3 +# Python 3.11 不会有这个问题 +uv pip install 'click>=8.2,<8.3' + +# 切换到 ROLL 目录以安装其依赖 +cd ../ROLL + +# 设置国内 PyPI 镜像源以加速下载 +PYPI_MIRROR="https://mirrors.aliyun.com/pypi/simple/" + +# 安装核心 PyTorch 组件 +uv pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 -i $PYPI_MIRROR + +# 安装transformer-engine,--no-build-isolation 避免因环境隔离导致找不到 torch +uv pip install transformer-engine[pytorch]==2.2.0 --no-build-isolation -i $PYPI_MIRROR + +# 安装预编译的 flash-attention,以匹配特定的 CUDA 和 PyTorch 版本 +uv pip install https://github.com/Dao-AILab/flash-attention/releases/download/v2.7.2.post1/flash_attn-2.7.2.post1+cu12torch2.6cxx11abiFALSE-cp310-cp310-linux_x86_64.whl + +# 安装其余依赖 +uv pip install -r requirements_torch260_vllm.txt -i $PYPI_MIRROR + +# (可选) 安装Tensorboard,用于查看训练指标 +uv pip install tensorboard -i $PYPI_MIRROR + +# 启动ROLL脚本(包含ROCK服务的启动) +bash examples/agentic_demo/run_agentic_pipeline_sokoban_sandbox_single_node.sh +``` + +### 方式二:使用系统环境启动(备选方案) + +为获得最佳兼容性,推荐使用 ROLL 官方提供的基础 Docker 镜像,因为它们已经预装了匹配的 CUDA、cuDNN 和其他基础库。 + +> [ROLL 官方镜像列表](https://alibaba.github.io/ROLL/zh-Hans/docs/Getting%20Started/Installation/image_address/) + + +#### 注意 +此方式会将所有 Python 包直接安装到您的当前环境(例如,容器的基础环境)中,可能会与系统自带的包或其他项目产生冲突。 + +由于 ROCK 无法复用环境,每次启动任务时都可能需要重新安装部分依赖,启动速度较慢且受网络影响。 + + +```bash +PYPI_MIRROR="https://mirrors.aliyun.com/pypi/simple/" + +# 安装ROCK的依赖 +cd ROCK +pip install . -i $PYPI_MIRROR +pip install ".[admin]" -i $PYPI_MIRROR + +# 安装ROLL的依赖 +cd ../ROLL +pip install -r requirements_torch260_vllm.txt -i $PYPI_MIRROR + +# 配置ROCK用uv启动的环境变量 +export ROCK_WORKER_ENV_TYPE=uv + +# 启动ROLL脚本(包含ROCK服务的启动) +bash examples/agentic_demo/run_agentic_pipeline_sokoban_sandbox_single_node.sh +``` + +至此,您已成功启动了 Sokoban 强化学习训练流程。祝您 Rock & Roll 愉快! + + +## 3. 多机部署 + +除了在单机上运行,您也可以将 **ROCK 服务** 和 **ROLL 训练** 部署在不同的机器上,通过网络进行通信。这是一种常见的服务化部署模式。 + +### 3.1 在机器 A 上部署 ROCK 服务 + +在一台独立的机器(或容器)上,参照[ROCK快速指南](./quickstart.md)部署并启动 ROCK 服务。 + +> **重要提示** +> 启动服务后,请记下ROCK服务的IP地址和端口,例如`http://192.168.1.10:8000`,后续步骤将需要这个地址。 + +### 3.2 在机器 B 上准备 ROLL 客户端 + +在另一台将要运行训练任务的机器上,执行以下操作。 + +1. 验证网络连通性 + +首先,使用 curl 命令检查是否能从机器 B 访问到机器 A 上的 ROCK 服务。 +```bash +# 将 : 替换为您的 ROCK 服务实际地址 +# 如果成功,会收到 ROCK 服务的响应 {"message":"hello, ROCK!"} +curl http://: +``` + +2. 准备 ROLL 环境 + +```bash +# 克隆 ROLL 仓库 +git clone https://github.com/alibaba/ROLL.git +cd ROLL + +# 安装依赖 +pip install -r requirements_torch260_vllm.txt -i https://mirrors.aliyun.com/pypi/simple/ +``` + +3. 配置 ROLL 连接地址 + +修改 ROLL 的配置文件,使其能够找到并连接到远程的 ROCK 服务。 +- 打开配置文件:examples/agentic_demo/agentic_val_sokoban_sandbox.yaml +- 找到 SokobanSandbox 下的 env_config 部分 +- 将 base_url 的值修改为您的 ROCK 服务地址 +```yaml +custom_envs: + SokobanSandbox: + env_config: + # 将这里的地址修改为您的 ROCK 服务地址 + # 例如: base_url: 'http://192.168.1.10:8000' + base_url: 'http://:' +``` + +4. 启动训练 +配置完成后,即可在机器 B 上启动 ROLL 训练脚本。 + +```bash +# 此脚本现在会通过网络请求机器 A 上的 ROCK 服务来创建环境 +bash examples/agentic_demo/run_agentic_pipeline_sokoban_sandbox_multi_nodes.sh +``` + +### 进阶:分布式 ROLL 训练 + +如果您希望将 ROLL 训练任务本身进行分布式部署,可以参考 ROLL 的官方分布式部署文档。 +> [快速上手:多节点部署指南](https://alibaba.github.io/ROLL/zh-Hans/docs/Getting%20Started/Quick%20Start/multi_nodes_quick_start) \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/model-service.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/model-service.md new file mode 100644 index 000000000..9a1d4b49c --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/model-service.md @@ -0,0 +1,115 @@ +--- +sidebar_position: 2 +--- + +# 模型服务 (Model Service)(实验性) + +ROCK提供的Model Service负责处理AI模型调用的通信,为代理(Agent)和训练框架(如Roll)或实际的LLM推理服务之间提供通信桥梁。 + +## 架构概述 + +模型服务使用文件系统作为通信媒介,实现代理和模型间的请求-响应机制。当代理需要调用模型时,请求首先写入日志文件,然后由负责监听的组件处理响应。当模型生成响应后,结果将写回日志文件,并由等待的代理读取。 + +## CLI命令 + +如果需要通过CLI使用模型服务, ROCK提供了一个CLI命令集,可以在沙箱中安装ROCK后, 通过 `rock model-service` 访问: + +### start命令 +开始模型服务进程 +```bash +rock model-service start --type [local|proxy] +``` + +参数: +- `--type`: 模型服务类型,可选`local`或`proxy`,默认为`local` + +### watch-agent命令 +监控代理进程,当进程退出时发送 SESSION_END 消息 +```bash +rock model-service watch-agent --pid <进程ID> +``` + +参数: +- `--pid`: 需要监控的代理进程ID + +### stop命令 +停止模型服务 +```bash +rock model-service stop +``` + +### anti-call-llm命令 +反调用LLM接口 +```bash +rock model-service anti-call-llm --index <索引> [--response <响应>] +``` + +参数: +- `--index`: 上一个LLM调用的索引,从0开始 +- `--response`: 上一次LLM调用的响应(可选) + +## 文件通信协议 + +模型服务使用文件进行进程间通信,定义了特定的标记格式用于区分请求和响应: + +### 请求格式 +``` +LLM_REQUEST_START{JSON请求数据}LLM_REQUEST_END{元数据JSON} +``` + +### 响应格式 +``` +LLM_RESPONSE_START{JSON响应数据}LLM_RESPONSE_END{元数据JSON} +``` + +### 会话结束标识 +``` +SESSION_END +``` + +元数据包含时间戳和索引信息,用于保证消息顺序和处理。 + +## 沙箱集成 + +### ModelServiceConfig +位于`rock/sdk/sandbox/model_service/base.py`,定义了沙箱中的模型服务配置: +- 工作目录 +- Python和模型服务安装命令 +- 会话环境变量 +- 各种命令模板 + +### ModelService类 +处理沙箱内模型服务的生命周期: +- `install()`: 在沙箱中安装模型服务依赖 +- `start()`: 启动模型服务 +- `stop()`: 停止模型服务 +- `watch_agent()`: 监控代理进程 +- `anti_call_llm()`: 执行反调用LLM操作 + +## 工作流程 + +1. 代理发起模型调用请求 +2. 请求被格式化并写入日志文件 +3. 模型服务监听日志文件,捕获新请求 +4. 运行时(Roll)处理请求并生成响应 +5. 响应写入日志文件 +6. 模型服务返回响应给代理 + +## 配置选项 + +### 服务配置 +- `SERVICE_HOST`: 服务主机地址,默认为"0.0.0.0" +- `SERVICE_PORT`: 服务端口,默认为8080 + +### 日志配置 +- `LOG_FILE`: 用以通信的日志文件路径,包含请求和响应数据 + +### 轮询配置 +- `POLLING_INTERVAL_SECONDS`: 轮询间隔,默认为0.1秒 +- `REQUEST_TIMEOUT`: 请求超时时间,默认为无限 + +### 标记配置 +定义了用于区分日志文件中不同类型消息的标记: +- `REQUEST_START_MARKER` / `REQUEST_END_MARKER` +- `RESPONSE_START_MARKER` / `RESPONSE_END_MARKER` +- `SESSION_END_MARKER` \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/python_sdk.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/python_sdk.md new file mode 100644 index 000000000..c1083f29b --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/python_sdk.md @@ -0,0 +1,265 @@ +--- +sidebar_position: 2 +--- + +# Python SDK 参考 + +本指南详细介绍如何使用 ROCK SDK 进行开发,包括沙箱环境管理和 GEM 环境交互。 + +## 1. 概述 + +ROCK SDK为开发者提供了便捷的Python接口来使用ROCK平台的功能,包括沙箱环境管理和GEM环境交互。 + +> **重要提示**: 使用 SDK 之前,请确保 ROCK Admin 服务正在运行。可以通过以下命令启动: +> ```bash +> rock admin start +> ``` + +## 2. Sandbox SDK + +### 2.1 基本沙箱操作 + +```python +import asyncio + +from rock.actions import CreateBashSessionRequest +from rock.sdk.sandbox.client import Sandbox +from rock.sdk.sandbox.config import SandboxConfig + +async def run_sandbox(): + """Run sandbox demo with admin server requirement. + + NOTE: This demo requires the admin server to be running for proper execution. + Make sure to start the admin server before running this script. + Default admin server port is 8080. + """ + # Create sandbox configuration + config = SandboxConfig(image="python:3.11", memory="8g", cpus=2.0) + + # Create sandbox instance + sandbox = Sandbox(config) + + # Start sandbox (connects to admin server) + await sandbox.start() + + # Create session in sandbox for command execution + await sandbox.create_session(CreateBashSessionRequest(session="bash-1")) + + # Execute command in sandbox session + result = await sandbox.arun(cmd="echo Hello ROCK", session="bash-1") + print("\n" + "*" * 50 + "\n" + result.output + "\n" + "*" * 50 + "\n") + + # Stop and clean up sandbox resources + await sandbox.stop() + +if __name__ == "__main__": + # Ensure admin server is running before executing + print("IMPORTANT: Make sure the admin server is running before executing this demo!") + print("Start the admin server with: rock admin start") + asyncio.run(run_sandbox()) +``` + +### 2.2 沙箱组管理 + +```python +from rock.sdk.sandbox.config import SandboxGroupConfig + +# 创建沙箱组配置 +config = SandboxGroupConfig( + image="python:3.11", + size=4, # 创建4个沙箱 + start_concurrency=2, # 并发启动级别为2 +) + +# 创建并启动沙箱组 +sandbox_group = SandboxGroup(config) +await sandbox_group.start() + +# 批量操作 +for sandbox in sandbox_group.sandbox_list: + await sandbox.run_in_session(Action(session="default", command="echo Hello")) + +# 批量停止 +await sandbox_group.stop() +``` + +### 2.3 配置示例 + +```python +config = SandboxConfig( + image="python:3.11", + auto_clear_seconds=60 * 20, + experiment_id="test", +) +``` + +### 2.4 沙箱加速配置 + +ROCK 提供沙箱网络加速功能,支持配置 APT、PIP 和 GitHub 镜像源,提升受限网络环境下的包下载速度。 + +#### 支持的加速类型 + +**APT 镜像配置** + +配置 APT 包管理器镜像源,加速 Debian/Ubuntu 软件包下载。 + +```python +from rock.sdk.sandbox.speedup import SpeedupType + +# 配置 APT 镜像 +await sandbox.network.speedup( + speedup_type=SpeedupType.APT, + speedup_value="http://mirrors.cloud.aliyuncs.com" +) +``` + +**PIP 镜像配置** + +配置 Python 包索引镜像,加速 pip 安装。 + +```python +# HTTP 镜像 +await sandbox.network.speedup( + speedup_type=SpeedupType.PIP, + speedup_value="http://mirrors.cloud.aliyuncs.com" +) + +# HTTPS 镜像 +await sandbox.network.speedup( + speedup_type=SpeedupType.PIP, + speedup_value="https://mirrors.aliyun.com" +) +``` + +**GitHub 加速** + +通过添加自定义 DNS 解析条目加速 GitHub 访问。 + +```python +await sandbox.network.speedup( + speedup_type=SpeedupType.GITHUB, + speedup_value="11.11.11.11" +) +``` + +#### 完整示例 + +```python +from rock.sdk.sandbox.speedup import SpeedupType +from rock.actions import RunMode + +async def setup_sandbox_with_speedup(): + """创建沙箱并配置加速""" + config = SandboxConfig(image="python:3.11") + sandbox = Sandbox(config) + + await sandbox.start() + + # 配置加速(在安装包之前配置) + await sandbox.network.speedup( + speedup_type=SpeedupType.APT, + speedup_value="http://mirrors.cloud.aliyuncs.com" + ) + + await sandbox.arun(cmd="apt-get update && apt-get install -y git", mode=RunMode.NOHUP) + + await sandbox.network.speedup( + speedup_type=SpeedupType.PIP, + speedup_value="https://mirrors.aliyun.com" + ) + + # speedup 不会主动安装 PIP,仅配置镜像源进行加速 + await sandbox.arun(cmd="pip install numpy", mode=RunMode.NOHUP) + + # 可以通过镜像 IP 加速 GitHub 访问 + await sandbox.network.speedup( + speedup_type=SpeedupType.GITHUB, + speedup_value="11.11.11.11" + ) + + return sandbox +``` + +#### 注意事项 + +1. **配置顺序**: 在安装包之前配置加速 +2. **HTTPS vs HTTP**: HTTPS 镜像不需要为 PIP 配置 trusted-host +3. **GitHub IP**: 不同区域可能需要不同的 IP 以获得最佳性能 +4. **持久性**: 配置在沙箱生命周期内持久有效 +5. **多次调用**: 后续的加速调用会覆盖之前的配置 +6. **PIP 安装**: speedup 功能仅配置镜像源,不会自动安装 PIP + +## 3. GEM SDK + +### 3.1 Python SDK 方式 + +```python +import random +import rock + +def main(): + """Main function to run the Sokoban demo with admin server requirement. + + NOTE: This demo requires the admin server to be running for proper execution. + Make sure to start the admin server before running this script. + """ + # Create environment using GEM standard interface + # NOTE: This requires the admin server to be running + env_id = "game:Sokoban-v0-easy" + env = rock.make(env_id) + + # Reset environment to initial state + observation, info = env.reset(seed=42) + print( + "\n" + + "=" * 80 + + "\nInitial Observation:\n" + + str(observation) + + "\n\nInitial Info:\n" + + str(info) + + "\n" + + "=" * 80 + + "\n" + ) + + # Run environment loop until termination + step_count = 0 + while True: + # Interactive environment operation with random actions + action = f"\\boxed{{{random.choice(['up', 'left', 'right', 'down'])}}}" + observation, reward, terminated, truncated, info = env.step(action) + + step_count += 1 + print( + "\n" + + "-" * 80 + + f"\nStep {step_count} - Action: {action}\nReward: {reward}\nObservation:\n{observation}\nInfo: {info}\nTerminated: {terminated}, Truncated: {truncated}\n" + + "-" * 80 + + "\n" + ) + + # Check if environment has reached terminal state + if terminated or truncated: + print("\n" + "=" * 80 + "\nEpisode finished!\n" + "=" * 80 + "\n") + break + + # Clean up environment resources + env.close() + +if __name__ == "__main__": + # Ensure admin server is running before executing + print( + "\n" + + "=" * 80 + + "\nIMPORTANT: Make sure the admin server is running before executing this demo!\nStart the admin server with: rock admin start\n" + + "=" * 80 + + "\n" + ) + main() +``` + +## 相关文档 +- [快速开始指南](../../Getting%20Started/quickstart.md) - 了解如何快速开始使用 ROCK SDK +- [API 文档](../api.md) - 查看 SDK 封装的底层 API 接口 +- [配置指南](../../User%20Guides/configuration.md) - 了解 SDK 相关的配置选项 +- [安装指南](../../Getting%20Started/installation.md) - 详细了解 ROCK 安装和配置 \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/runtime-env.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/runtime-env.md new file mode 100644 index 000000000..db33f9567 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/runtime-env.md @@ -0,0 +1,111 @@ +# RuntimeEnv SDK Reference + +RuntimeEnv 模块用于在沙箱中管理语言运行时环境(目前提供了 Python / Node.js)。 + +## 快速开始(使用示例) + +```python +from rock.sdk.sandbox import Sandbox +from rock.sdk.sandbox.config import SandboxConfig +from rock.sdk.sandbox.runtime_env import RuntimeEnv, NodeRuntimeEnvConfig + +sandbox_config = SandboxConfig() +sandbox = Sandbox() +await sandbox.start() + +node_runtime_env_config = NodeRuntimeEnvConfig(version="default") +env = await RuntimeEnv.create(sandbox, node_runtime_env_config) + +await env.run("node --version") +``` + +## RuntimeEnv.create + +异步工厂方法,根据配置创建 RuntimeEnv 实例并初始化,自动注册到 `sandbox.runtime_envs`。 + +```python +from rock.sdk.sandbox.runtime_env import RuntimeEnv, NodeRuntimeEnvConfig + +env = await RuntimeEnv.create( + sandbox, + NodeRuntimeEnvConfig(version="22.18.0"), +) + +# 自动注册,可通过 sandbox.runtime_envs[env.runtime_env_id] 访问 +print(env.runtime_env_id in sandbox.runtime_envs) # True +``` + +## wrapped_cmd + +包装命令,将 `bin_dir` 加入 PATH,确保优先使用运行时环境中的可执行文件。 + +```python +# 默认 prepend=True,bin_dir 优先于系统 PATH +wrapped = env.wrapped_cmd("node script.js") +# 返回: bash -c 'export PATH=/tmp/rock-runtime-envs/node/22.18.0/xxx/runtime-env/bin:$PATH && node script.js' + +``` + +## run + +在运行时环境中执行命令。内部基于 `wrapped_cmd` 实现,自动将 `bin_dir` 加入 PATH。 + +```python +await env.run("node script.js") +await env.run("npm install express") + +# 指定超时时间 +await env.run("npm install some-big-package", wait_timeout=1200) +``` + +## PythonRuntimeEnvConfig + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `type` | `Literal["python"]` | `"python"` | 类型标识 | +| `version` | `"3.11" \| "3.12" \| "default"` | `"default"` | Python 版本,默认 3.11 | +| `pip` | `list[str] \| str \| None` | `None` | pip 包列表或 requirements.txt 路径 | +| `pip_index_url` | `str \| None` | 环境变量 | pip 镜像源 | + +## NodeRuntimeEnvConfig + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `type` | `Literal["node"]` | `"node"` | 类型标识 | +| `version` | `"22.18.0" \| "default"` | `"default"` | Node 版本,默认 22.18.0 | +| `npm_registry` | `str \| None` | `None` | npm 镜像源 | + +## 自定义 RuntimeEnv 实现约束 + +自定义 RuntimeEnv 需遵循以下规则: + +1. **定义 `runtime_env_type` 类属性**:作为类型标识符,用于自动注册到 RuntimeEnv 工厂 +2. **重写 `_get_install_cmd()`**:返回安装命令 +3. **安装命令最后必须**:将目录重命名为 `runtime-env` + + +## NodeRuntimeEnv 简化版实现示例 + +```python +from rock.sdk.sandbox.runtime_env import RuntimeEnv, RuntimeEnvConfig +from typing import Literal +from pydantic import Field +from typing_extensions import override + +# Config 类:定义配置类型,用于 RuntimeEnv.create() 路由到对应实现 +class NodeRuntimeEnvConfig(RuntimeEnvConfig): + type: Literal["node"] = "node" # 必须与 runtime_env_type 一致 + +# RuntimeEnv 实现类:定义如何安装和运行该运行时环境 +class NodeRuntimeEnv(RuntimeEnv): + runtime_env_type = "node" # 自动注册到 RuntimeEnv._REGISTRY + + @override + def _get_install_cmd(self) -> str: + # 下载 Node 二进制包并解压,最后重命名为 runtime-env + return ( + "wget -q -O node.tar.xz https://npmmirror.com/mirrors/node/v22.18.0/node-v22.18.0-linux-x64.tar.xz && " + "tar -xf node.tar.xz && " + "mv node-v22.18.0-linux-x64 runtime-env" + ) +``` diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/sandbox-agent.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/sandbox-agent.md new file mode 100644 index 000000000..1ae75e3b1 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/sandbox-agent.md @@ -0,0 +1,49 @@ +--- +sidebar_position: 3 +--- + +# 沙箱代理 (Sandbox Agent)(实验性) + +沙箱代理是ROCK框架中用于在隔离环境中运行AI智能体任务的组件,提供安全且可控制的智能体执行环境。代理可以与模型服务(Model Service)集成,实现LLM模型调用的优雅处理。 + +## 架构概述 + +沙箱代理通过在隔离的沙箱环境中初始化和执行智能体任务,包括安装必要的依赖、配置运行环境等步骤。代理系统支持多种不同的智能体类型,如SWE-agent和IFlow CLI等,每种类型都有其特定的配置和实现方式。 + +代理可以与模型服务集成,在任务执行期间处理AI模型调用。当代理需要查询或调用AI模型时,模型服务会在后台处理模型通信,使代理专注于任务执行。 + + +## Sandbox Agent 初始化流程 + +1. 创建沙箱环境和代理实例 +2. 调用`init()`方法初始化代理 +3. 在沙箱中创建专用的bash会话 +4. 执行预启动命令(如环境配置) +5. 安装必要的依赖(Python、Node.js等) +6. 安装特定的智能体工具(如SWE-agent或IFlow CLI) +7. 如果配置了模型服务,将同步初始化模型服务 + +## Sandbox Agent 执行流程 + +1. 准备任务运行参数(问题陈述、项目路径等) +2. 调用`run()`方法执行任务 +3. 准备运行所需的配置文件, 并将配置文件上传到沙箱环境(如果需要) +4. 执行Agent +6. 如果配置了模型服务,同步监控Agent进程 +7. 等待任务完成并返回结果 + +## Model Service 集成能力 + +沙箱Agent支持与模型服务的无缝集成,为AI模型调用提供通信桥梁。这种集成允许Agent通过文件系统通信协议与模型服务交互,实现异步的请求-响应机制。在Agent初始化时, 可以将Agent请求的LLM地址配置为model-service server的地址(如默认提供http://localhost:8080/v1/chat/completions), 从而利用model-service代理访问实际推理服务; 当Agent与模型服务集成时的工作流程: + +### 任务开始前 +1. 调用`start_model_service()`启动模型服务 +2. 调用`watch_agent()`设置对Agent进程的监控 + +### Agent调用LLM时 +1. Agent发起模型调用请求 +2. 请求通过文件通信协议写入文件 +3. 模型服务监听器捕获请求 +4. 实际的AI模型返回响应 +5. 响应通过文件通信协议写回 +6. Agent读取响应并继续执行 \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/sandbox.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/sandbox.md new file mode 100644 index 000000000..5a94c93a5 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/Python SDK References/sandbox.md @@ -0,0 +1,62 @@ +# Sandbox SDK 参考 + +## `arun` +`arun()` 在 `nohup` 模式下提供了两个关键参数,帮助 Agent / 调用方在“执行”与“查看”之间按需解耦: + +1. **`response_limited_bytes_in_nohup`**(int 型) + 限制返回内容的最大字符数(例如 `64 * 1024`),适合仍需立刻查看部分日志、但必须控制带宽的场景。默认值 `None` 表示不加限制。 + +2. **`ignore_output`**(bool,默认 `False`) + 当设为 `True` 时,`arun()` 不再读取 nohup 输出文件,而是在命令执行完毕后立即返回一段提示信息(包含输出文件路径、**文件大小**及查看方式)。日志仍写入 `/tmp/tmp_.out`,后续可通过 `read_file`、下载接口或自定义命令按需读取,实现"执行"与"查看"彻底解耦。返回的文件大小信息可帮助用户决定是直接下载还是分块读取。 + +```python +from rock.sdk.sandbox.client import Sandbox +from rock.sdk.sandbox.config import SandboxConfig +from rock.sdk.sandbox.request import CreateBashSessionRequest + +config = SandboxConfig( + image=f"{image}", + xrl_authorization=f"{xrl_authorization}", + user_id=f"{user_id}", + cluster=f"{cluster}", +) +sandbox = Sandbox(config) + +session = sandbox.create_session(CreateBashSessionRequest(session="bash-1")) + +# 示例 1:限制最多 1024 个字符 +resp_limit = asyncio.run( + sandbox.arun( + cmd="cat /tmp/test.txt", + mode="nohup", + session="bash-1", + response_limited_bytes_in_nohup=1024, + ) +) + +# 示例 2:完全跳过日志读取,后续再通过 read_file / 下载获取 +resp_detached = asyncio.run( + sandbox.arun( + cmd="bash run_long_job.sh", + mode="nohup", + session="bash-1", + ignore_output=True, + ) +) +print(resp_detached.output) +# Command executed in nohup mode without streaming the log content. +# Status: completed +# Output file: /tmp/tmp_xxx.out +# File size: 15.23 MB +# 可通过 Sandbox.read_file(...) / 下载接口 / cat /tmp/tmp_xxx.out 查看日志 +``` + +## `read_file_by_line_range` +功能说明: 按行范围异步读取文件内容,支持自动分块读取和会话管理。主要特性包括大文件自动分块读取、自动统计文件总行数、内置重试机制(3次重试)、参数验证。以下是使用示例: +```python +# 读取整个文件 +response = await read_file_by_line_range("example.txt") + +# 读取指定行范围 +response = await read_file_by_line_range("example.txt", start_line=1, end_line=2000) +``` \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/api.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/api.md new file mode 100644 index 000000000..06f44c326 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/References/api.md @@ -0,0 +1,194 @@ +--- +sidebar_position: 1 +--- + +# API 参考 + +本指南详细介绍 ROCK 平台提供的核心 API 服务,包括沙箱环境管理和 GEM 环境交互。 + +## 1. 概述 + +ROCK平台提供两种核心API服务: +- Sandbox API:沙箱环境管理 +- GEM API:GEM环境交互 + +所有 API 接口都遵循 RESTful 设计原则,支持 JSON 格式的数据交换。 + +## 2. Sandbox API + +沙箱环境全生命周期管理功能: + +### 沙箱管理接口 + +1. **Start Sandbox** - 启动沙箱环境 + - 创建一个新的沙箱实例 + - 支持指定镜像、资源配置等参数 + +2. **Start Sandbox Async** - 异步启动沙箱环境 + - 异步方式创建沙箱实例 + - 适用于需要快速响应的场景 + +3. **Check Sandbox Alive Status** - 检查沙箱存活状态 + - 验证沙箱是否正常运行 + +4. **Get Sandbox Statistics** - 获取沙箱统计信息 + - 获取沙箱的资源使用统计 + +5. **Get Sandbox Status** - 获取沙箱详细状态 + - 获取沙箱的完整状态信息 + +6. **Stop Sandbox** - 停止沙箱环境 + - 安全关闭沙箱实例 + +7. **Commit Sandbox** - 提交沙箱为镜像 + - 将当前沙箱状态保存为新镜像 + +### 命令执行接口 + +8. **Execute Command** - 在沙箱中执行命令 + - 直接在沙箱中运行指定命令 + +9. **Create Bash Session** - 创建Bash会话 + - 创建持久化的Bash会话环境 + +10. **Run Command in Session** - 在会话中执行命令 + - 在已创建的会话中执行命令 + +11. **Close Session** - 关闭会话 + - 释放会话资源 + +### 文件操作接口 + +12. **Read File** - 读取沙箱文件 + - 从沙箱中读取指定文件内容 + +13. **Write File** - 写入沙箱文件 + - 向沙箱中写入文件 + +14. **Upload File** - 上传文件到沙箱 + - 将本地文件上传到沙箱 + +## 3. GEM API + +GEM环境交互功能: + +1. **Make Environment** - 创建GEM环境 + - 初始化一个新的GEM环境实例 + +2. **Reset Environment** - 重置GEM环境 + - 将GEM环境重置到初始状态 + +3. **Step Environment** - 执行GEM环境步骤 + - 在GEM环境中执行一个动作步骤 + +4. **Close Environment** - 关闭GEM环境 + - 释放GEM环境资源 + +## 4. HTTP API 使用示例 + +### 4.1 Sandbox API 示例 + +#### 启动沙箱 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/start' \ +-H 'Content-Type: application/json' \ +-d '{ + "image": "python:3.11", + "resources": { + "cpu": "2", + "memory": "8g" + } +}' +``` + +#### 异步启动沙箱 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/start_async' \ +-H 'Content-Type: application/json' \ +-d '{ + "image": "python:3.11", + "resources": { + "cpu": "2", + "memory": "8g" + } +}' +``` + +#### 执行命令 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/execute' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345", + "command": "ls -la" +}' +``` + +#### 创建会话 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/create_session' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345", + "session": "my_session" +}' +``` + +#### 在会话中执行命令 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/run_in_session' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345", + "session": "my_session", + "command": "python script.py" +}' +``` + +#### 上传文件 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/upload' \ +-F 'file=@./local_file.txt' \ +-F 'target_path=./remote_file.txt' \ +-F 'sandbox_id=sandbox-12345' +``` + +#### 停止沙箱 +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/stop' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345" +}' +``` + +### 4.2 GEM API 示例 + +```bash +# 创建GEM环境 +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/make' \ +-H 'Content-Type: application/json' \ +-d '{"env_id": "game:Sokoban-v0-easy"}' + +# 重置环境 +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/reset' \ +-H 'Content-Type: application/json' \ +-d '{"sandbox_id": "sandbox-12345", "seed": 42}' + +# 执行步骤 +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/step' \ +-H 'Content-Type: application/json' \ +-d '{"sandbox_id": "sandbox-12345", "action": "random_action"}' + +# 关闭环境 +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/close' \ +-H 'Content-Type: application/json' \ +-d '{"sandbox_id": "sandbox-12345"}' +``` + +## 相关文档 + +- [快速开始指南](../Getting%20Started/quickstart.md) - 了解如何快速开始使用 ROCK API +- [Python SDK 文档](./Python%20SDK%20References/python_sdk.md) - 学习如何使用 SDK 调用 API +- [配置指南](../User%20Guides/configuration.md) - 了解 API 相关的配置选项 +- [安装指南](../Getting%20Started/installation.md) - 详细了解 ROCK 安装和配置 diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Release Notes/index.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Release Notes/index.md new file mode 100644 index 000000000..948b23123 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Release Notes/index.md @@ -0,0 +1,5 @@ +--- +sidebar_position: 1 +--- +# 版本说明 +* [release v1.1.0](v1.1.0.md) \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Release Notes/v1.1.0.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Release Notes/v1.1.0.md new file mode 100644 index 000000000..27f7c8ff0 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/Release Notes/v1.1.0.md @@ -0,0 +1,157 @@ +# v1.1.0 + +## 发布日期 +2026 年 1 月 23 日 + +## 概览 +这是一次重大版本发布,引入了多项强大的新功能 同时还包含显著的性能提升、系统优化与更强的可观测性能力。 + +--- + +## SDK + +### 新功能 + +#### Model Service(实验性) +**[Model Service 参考文档](../References/Python%20SDK%20References/model-service.md)** + +提供完整的模型服务能力,包括: +- 支持文件处理器的本地模型服务器 +- 用于无缝交互的模型客户端 +- 支持模型请求代理(Proxy) +- 通过 CLI 参数按“类型”选择模型 +- 与 SWE Agent 安装并发初始化 +- 用于线程安全操作的锁机制 + + +#### Sandbox Agent(实验性) +**[Sandbox Agent 参考文档](../References/Python%20SDK%20References/sandbox-agent.md)** + +用于在ROCK的Sandbox中快速安装Agent的功能: +- 简易的 Agent 安装接口 +- 与Model-Service快速集成的能力 +- 支持多种类型的Agent在隔离的沙箱环境中本地运行 + + +#### 沙箱加速 (Sandbox Speedup) +**[沙箱加速参考文档](../References/Python%20SDK%20References/python_sdk.md)** + +提供针对沙箱环境的网络优化与镜像配置能力: +- 支持一键配置 APT 公共镜像源 +- 支持 PIP 镜像源加速(自动处理 HTTP/HTTPS 协议及信任主机配置) +- 通过 Hosts 映射实现 GitHub 访问加速 +- 采用非侵入式配置,仅优化源地址而不强制执行安装 +- 基于策略(Strategy)的 URL 自动解析与标准化逻辑 +--- + +### 增强 + +#### Environment Builder +- 新增 `build_remote` 参数,用于远程环境构建 +- 更新超时配置,提供更好的控制能力 +- 在 `arun` 的 ignore_output 中增强文件大小信息展示 + +#### 性能优化 +- 优化 PID 提取逻辑,使用兼容 bash 的模式 +- 提升 `arun` 方法性能 +- 改进文件处理相关操作 + +#### API 改进 +- 为运行 API execute 操作增加更多可选变量 +- 增强请求/响应处理 +- 改进错误报告,包含文件大小细节 +- 在`start` 方法中根据透传的异常码优化返回错误类型 + +--- + +### Bug 修复 +- 修复 PID 提取逻辑,改用兼容 bash 的模式 +- 修正 PIPE 重定向策略 +- 修复写集群(write cluster)操作的状态获取 +- 改进服务启动失败时的异常处理 + +--- + +## Admin + +### 新功能 + +#### 增强的可观测性 +- 为过期的时间线(timelines)增加 OpenTelemetry 指标清理 +- 为测试用例提供内存指标读取器(in-memory metric reader) +- 增强 Model Service 操作日志 +- 将 pod 信息加入 OpenTelemetry 指标的基础标签中 +- 增加集群维度的ray资源指标监控 + +#### 系统改进 +- 支持只读挂载路径(read-only mount path),提升安全性 +- 增强写集群状态获取 +- 改进服务启动异常处理 +- 运行配置中增加sandbox标准规格与上限规格 +- 增强了 HTTP 层的异常处理器,确保错误码能够正确传播到上层调用方 + +--- + +### 增强 + +#### Actor 系统 +- 重构 actor 的 pip 依赖以便更好管理 +- 增强 actor 依赖更新机制 +- 改进 actor 初始化流程 +- 创建 Actor 时,同步部署配置中的资源需求至 Ray 集群 + +#### 镜像管理 +- Image Mirror 增强重试支持 +- 改进镜像构建并支持实验 ID 追踪 +- 升级镜像标签管理 + +--- + +### Bug 修复 +- 修复写集群操作的状态获取 +- 修正 PIPE 重定向策略 +- 改进服务启动失败时的异常处理 + +--- + +## 全局系统变更 + +### 重构 +- 将 `is_absolute_db_path` 移至 database 模块 +- 移除未使用的 API key 并清理测试 +- 移除冗余的 `DockerDeploymentConfig` 导入 + +### 日志改进 +- 更新 logger 格式以提升可读性 +- 为 Sandbox 类增加 `__str__` 与 `__repr__` 方法 +- 在 `init_logger` 中阻止 logger 传播(propagation) +- 为 CLI 的配置加载增加日志 + +### CLI 增强 +- 增加系统资源限制 +- 增强 EnvHub 预检查功能 +- 改进 CLI 命令结构与组织 + +### 文档 +- 增加全面的发布说明 +- 创建 ROCK & ROLL 快速入门指南 +- 增强 GitHub Actions CI 工作流 +- 改进 Issue 模板以便更好地报告 Bug +- 增加 GitHub 指标统计页面 + +### 测试 +- 使用内存指标读取器优化测试用例 +- 增强新功能测试覆盖率 +- 改进测试加载器路径解析 + +--- + +## 已知问题 +- 目前暂无 + +## 贡献者 +感谢所有为本次发布做出贡献的贡献者! + +## 下一步计划 +- 增强文档与教程 +- 进一步的性能优化与 Bug 修复 \ No newline at end of file diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/User Guides/configuration.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/User Guides/configuration.md new file mode 100644 index 000000000..a212189bc --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/User Guides/configuration.md @@ -0,0 +1,188 @@ +--- +sidebar_position: 4 +--- + +# 配置指南 + +本指南详细介绍如何配置 ROCK 环境以满足不同的使用需求,包括本地开发、测试和生产部署。 + +## 1. 环境变量配置 + +ROCK 支持通过环境变量配置关键参数。以下是主要的环境变量: + +```bash +export ROCK_BASE_URL=http://localhost:8080 # ROCK服务基础URL +export ROCK_LOG_LEVEL=INFO # 日志级别 +export ROCK_LOGGING_PATH=/path/to/logs # 日志文件路径,默认 None (输出到控制台) +export ROCK_LOGGING_FILE_NAME=rocklet.log # 日志文件名,默认 "rocklet.log", 启动admin时可以自定义日志文件名, 如admin.log +export ROCK_LOGGING_LEVEL=INFO # 日志输出级别,默认 "INFO" +export ROCK_WORKER_ENV_TYPE=local # 运行时环境类型,可选值: local, docker, uv, pip +``` + +更多环境变量可参考 `rock/env_vars.py` 文件。 + +### 1.1 运行时环境 (Runtime Environments) + +ROCK 提供了多种不同的运行时环境来满足不同场景的需求,选择通过环境变量 `ROCK_WORKER_ENV_TYPE` 进行配置。每种环境有不同的部署要求、性能特征和适用场景。每种环境都有其独特的优势和限制,开发者可以根据部署环境的需要选择最适合的运行时环境。 + +#### 1.1.1 Docker 运行时环境 + +Docker 运行时环境适用于已经预安装了所需依赖的 Docker 镜像环境。这种环境要求部署环境中直接可用 `/tmp/miniforge/bin/rocklet` 可执行文件。 + +**挂载配置:** +- `/tmp/miniforge` - 包含预安装的 Python 环境 +- `/tmp/local_files` - 包含执行所需的本地文件 + +**启动命令:** +```bash +chmod +x /tmp/local_files/docker_run.sh && /tmp/local_files/docker_run.sh +``` + +**适用场景:** +- 容器化部署环境 +- 已经构建了包含 `rocklet` 的自定义 Docker 镜像 +- 适合生产环境,启动速度快 + +**要求:** +- 需要使用定制的 Docker 镜像,其中包含 `/tmp/miniforge/bin/rocklet` 可执行文件 +- Docker 环境支持 + +#### 1.1.2 本地运行时环境 + +本地运行时环境直接利用当前部署环境的 Python 环境和项目文件。该环境要求宿主机和容器之间具有相同的操作系统,以便能够直接挂载虚拟环境和 Python 解释器。 + +**挂载配置:** +- `python_env_path` - Python 环境路径 +- `project_root` - 项目根目录 +- `.venv` - 虚拟环境目录(挂载为容器中的 `/tmp/miniforge`) +- `local_files` - 执行所需的本地文件 + +**启动命令:** +```bash +chmod +x /tmp/local_files/docker_run.sh && /tmp/local_files/docker_run.sh +``` + +**适用场景:** +- 开发环境 +- 宿主机和目标容器使用相同操作系统的场景 +- 需要快速重新使用现有 Python 环境 + +**要求:** +- 相同的操作系统(主机/容器) +- 可直接访问当前部署的 `.venv` 虚拟环境 +- Python 解释器路径兼容 + +#### 1.1.3 UV 运行时环境 + +UV 运行时环境只依赖于可用的 ROCK 项目,但初始化相对较慢且网络要求较高。这种环境最适合没有预配置环境的场景。它从原始项目重新构建 rocklet 环境。这是推荐在 Mac 操作系统上使用的环境。 + +**挂载配置:** +- `project_root` - 项目根目录(挂载为容器中的 `/tmp + project_root`) +- `local_files` - 执行所需的本地文件 + +**启动命令:** +```bash +chmod +x /tmp/local_files/docker_run_with_uv.sh && /tmp/local_files/docker_run_with_uv.sh '' +``` + +**适用场景:** +- Mac 操作系统 +- 跨操作系统启动 +- 没有预配置环境的场景 +- 没有使用 uv 管理 Rock + +**优势:** +- 无需预构建镜像 +- 跨平台兼容性好 +- 特别适合开发和测试 + +**限制:** +- 初始化速度较慢 +- 网络要求较高 +- 启动时间较长 + +#### 1.1.4 PIP 运行时环境 + +PIP 运行时环境使用 pip 在容器内安装所需依赖。这种环境适合快速设置并能在容器中完成依赖安装的场景,是默认的运行时环境。它不需要预先构建包含依赖的镜像,通过 pip 直接管理 Python 包。 + +**挂载配置:** +- `local_files` - 包含执行所需的本地文件 + +**启动命令:** +```bash +chmod +x /tmp/local_files/docker_run_with_pip.sh && /tmp/local_files/docker_run_with_pip.sh +``` + +**适用场景:** +- 使用PIP源安装的ROCK +- 快速测试ROCK + +**优势:** +- 简单的部署设置 + +**限制:** +- 依赖安装时间较长 +- 需要网络访问以安装依赖包 +- 每次启动时都需要安装依赖 + +#### 1.1.5 配置指南 + +根据不同的使用场景,可以参考以下选择指南: + +| 场景 | 推荐环境 | 原因 | +|------|----------|------| +| 生产环境 | Docker 运行时 | 快速启动,稳定性能 | +| 开发环境,同一 OS | 本地运行时 | 环境重用,开发周期快 | +| Mac 开发 | UV 运行时 | 支持最佳的跨平台兼容性 | +| 跨平台开发 | UV 运行时 | 避免环境兼容性问题 | +| 快速测试 | UV 运行时 | 无需预配置工作 | +| PIP源安装 | PIP 运行时 | 直接使用 pip 安装依赖 | + +这些运行时环境通过 `ROCK_WORKER_ENV_TYPE` 环境变量进行配置,该变量可设置为 "local"、"docker"、"uv" 或 "pip"。 + +### 1.2 日志配置 + +在日志配置方面,ROCK 的日志系统具有以下特性: + +- 日志系统不能同时输出到文件和控制台,只有当设置了 `ROCK_LOGGING_PATH` 时,日志才会输出到指定文件,否则输出到控制台。 +- `ROCK_LOGGING_LEVEL` 用于控制日志输出级别,`ROCK_LOG_LEVEL` 用于通用日志级别设置。 + +## 2. 分布式部署要求 + +由于 ROCK 支持分布式部署,当在 Ray 集群的不同节点上运行时,需要满足以下一致性要求: + +#### 目录结构一致性 +在所有 Ray 节点上,必须保证以下目录结构完全一致: +- ROCK 项目仓库目录 +- `.venv` 虚拟环境目录 +- `.venv` 依赖的 base Python 目录 + + +#### 挂载要求 +ROCK 的启动依赖于挂载 ROCK 项目和对应的 base Python 环境,要求在多机环境中保持一致性: + +#### 验证分布式配置 +可以通过以下方式验证分布式部署配置: + +```bash +# 在所有节点上检查目录一致性 +ls -la /path/to/rock +ls -la /path/to/rock/.venv +ls -la $ROCK_PYTHON_ENV_PATH + +# 验证 Python 环境可用性 +$ROCK_PYTHON_ENV_PATH/bin/python --version + +# 检查所有节点上的环境变量设置 +echo $ROCK_PYTHON_ENV_PATH +echo $ROCK_PROJECT_ROOT +``` + + + +## 相关文档 + +- [快速开始指南](../Getting%20Started/quickstart.md) - 了解如何快速搭建 ROCK 环境 +- [API 文档](../References/api.md) - 查看沙箱相关的 API 接口 +- [Python SDK 文档](../References/Python%20SDK%20References/python_sdk.md) - 学习如何使用 SDK 配置沙箱 +- [安装指南](../Getting%20Started/installation.md) - 详细了解 ROCK 安装和配置 diff --git a/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/overview.md b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/overview.md new file mode 100644 index 000000000..a02536f50 --- /dev/null +++ b/docs/i18n/zh-Hans/docusaurus-plugin-content-docs/version-1.1.x/overview.md @@ -0,0 +1,40 @@ +--- +sidebar_position: 1 +--- + +# 概览 + +ROCK (Reinforcement Open Construction Kit) 是一个开源的强化学习环境开发框架,旨在简化强化学习环境的开发、部署和管理流程。 + +## 什么是 ROCK + +ROCK (Reinforcement Open Construction Kit) 是一个开源强化学习环境开发框架。通过使用 ROCK,开发者可以快速地开发强化学习环境,并结合其他强化学习训练框架,实现高效的强化学习训练。 + +ROCK 提供了完整的沙箱环境管理功能,支持容器化部署,能够实现环境的快速创建、运行和销毁。同时,ROCK 兼容 GEM 协议,为强化学习环境提供了标准化的接口。 + +## ROCK 的核心功能 + +1. **简化开发流程**:简化强化学习环境的开发、构建和管理流程,支持多种开源的强化学习环境 +2. **大规模调度部署**:支持快速强化学习环境的大规模调度部署,通过 GEM 协议可以方便地访问强化学习环境 +3. **框架集成**:与其他强化学习训练框架集成,实现大规模可扩展的强化学习训练 + +## ROCK 的价值 + +ROCK 为不同角色的工程师提供了显著价值: + +- **强化学习算法工程师**:ROCK 可以简化强化学习环境的开发流程,让工程师专注于算法实现 +- **强化学习应用工程师**:ROCK 可以进行快速强化学习环境的大规模部署,提高应用开发效率 + +## 相关文档 + +如果您是第一次使用 ROCK,建议按以下顺序阅读文档: +1. [快速开始指南](./Getting%20Started/quickstart.md) - 快速搭建开发环境 +2. [配置指南](./User%20Guides/configuration.md) - 配置您的 ROCK 环境 +3. [Python SDK 文档](./References/Python%20SDK%20References/python_sdk.md) - 学习如何使用 Python SDK 进行开发 +4. [API 文档](./References/api.md) - 了解完整的 API 接口 +5. [安装指南](./Getting%20Started/installation.md) - 详细了解 ROCK 安装和配置 + + + + + diff --git a/docs/versioned_docs/version-1.1.x/Getting Started/installation.md b/docs/versioned_docs/version-1.1.x/Getting Started/installation.md new file mode 100644 index 000000000..c45b09a8f --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/Getting Started/installation.md @@ -0,0 +1,143 @@ +--- +sidebar_position: 3 +--- + +# Installation + +This document explains how to install and set up the ROCK development environment using both `uv` and `pip`. The project is a Reinforcement Open Construction Kit that supports various components. + +## Using uv (Recommended) + +### Quick Install All Dependencies + +```bash +# Install all dependencies including optional ones +uv sync --all-extras + +# Install development/testing dependencies +uv sync --all-extras --all-groups +``` + +### Install Different Dependency Groups + +#### Core Dependencies Only +```bash +uv sync +``` + +#### Admin Component Dependencies +```bash +uv sync --extra admin +``` + +#### Rocklet Execution Environment Dependencies +```bash +uv sync --extra rocklet +``` + + +#### All Dependencies at Once +```bash +uv sync --all-extras +``` + +#### Development/Testing Dependencies +```bash +uv sync --all-extras --group test +``` + +## Using pip + +### Install from pip source + +#### Core Dependencies Only +```bash +pip install rl-rock +``` + +#### Admin Component Dependencies +```bash +pip install "rl-rock[admin]" +``` + +#### Rocklet Execution Environment Dependencies +```bash +pip install "rl-rock[rocklet]" +``` + +#### Builder Dependencies +```bash +pip install "rl-rock[builder]" +``` + +#### Install All Optional Dependencies +```bash +pip install "rl-rock[all]" +``` + +### Install with pip from source code + +#### Core Dependencies Only +```bash +pip install . +``` + +#### Admin Component Dependencies +```bash +pip install ".[admin]" +``` + +#### Rocklet Execution Environment Dependencies +```bash +pip install ".[rocklet]" +``` + +#### Builder Dependencies +```bash +pip install ".[builder]" +``` + +#### Install All Optional Dependencies +```bash +pip install ".[all]" +``` + +## Available Entry Points + +The package provides the following command line scripts: + +- `rocklet`: ROCK execution environment server (rock.rocklet.server:main) +- `admin`: Admin management server (rock.admin.main:main) +- `envhub`: Environment hub server (rock.envhub.server:main) +- `rock`: Main ROCK command line interface (rock.cli.main:main) + +## Development Setup + +### Using uv (Recommended) + +```bash +# Clone and set up development environment +git clone +cd ROCK +uv sync --all-extras --group test + +# Run tests +uv run pytest + +``` + +### Using pip + +```bash +# For development, install in editable mode with all extras +pip install -e ".[all]" + +# Or separately +pip install -e . +pip install ".[admin]" ".[rocklet]" ".[builder]" # Optional extras +``` + +## Additional Notes + +- The project is configured to use the Alibaba cloud PyPI mirror by default: `https://mirrors.aliyun.com/pypi/simple/` +- For local development, running tests requires the `test` dependency group diff --git a/docs/versioned_docs/version-1.1.x/Getting Started/quickstart.md b/docs/versioned_docs/version-1.1.x/Getting Started/quickstart.md new file mode 100644 index 000000000..2f14808f5 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/Getting Started/quickstart.md @@ -0,0 +1,166 @@ +--- +sidebar_position: 2 +--- + +# Getting Started + +This guide will demonstrate how to use ROCK to create and manage reinforcement learning environments through complete examples. + +## 1. Environment Preparation + +We recommend starting ROCK on Linux systems to maximize dependency reuse and improve environment startup speed. If you need to try on macOS, please refer to the [MacOS Startup](#7-macos-startup) section. + +Before starting, please ensure your system has the following dependencies installed: + +### 1.1 System Requirements + +- **Docker**: ROCK uses Docker for containerized environment management +- **uv**: ROCK uses uv for dependency management and virtual environment creation + +### 1.2 Verify Dependency Installation + +```bash +# Verify Docker installation +docker --version + +# Verify Docker image, and example depends on python:3.11 image +docker pull python:3.11 + +# Verify uv installation +uv --version +``` + +### 1.3 Project Initialization + +```bash +# Clone repository +git clone +cd ROCK + +# Create virtual environment (using uv-managed Python, use python 3.11 as an example) +uv venv --python 3.11 --python-preference only-managed + +# Install all dependency groups +uv sync --all-extras +``` + +> **Important Note**: To ensure ROCK can correctly mount the project and virtual environment along with its base Python interpreter, it is strongly recommended to use uv-managed Python environments to create virtual environments rather than system Python. + +## 2. Activate Virtual Environment + +Before running any ROCK commands, you need to activate the virtual environment. Ensure sys.base_prefix is a uv-managed environment, such as `/root/.local/share/uv/python/cpython-3.11.8-linux-x86_64-gnu` or similar paths. + +```bash +# Activate virtual environment +source .venv/bin/activate + +# Verify Python environment +python -c "import sys; print('Base prefix:', sys.base_prefix)" +``` + +> **Verification Point**: Ensure the output base prefix path points to a uv-managed Python environment, not system Python. + +## 3. Verify Environment Configuration + +After activating the virtual environment, verify that dependencies are installed correctly: + +```bash +# Check key dependencies +python -c "import rock; print(\"Hello ROCK\")" +``` + +## 4. Start ROCK Service + +After activating the virtual environment, start the ROCK Admin service on project root: + +```bash +# Ensure virtual environment is activated +source .venv/bin/activate + +# Start ROCK Admin service (local environment) +rock admin start +``` + +After the service starts, you will see output similar to the following: + +``` +INFO: Started server process [12345] +INFO: Waiting for application startup. +INFO: Application startup complete. +INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit) +``` + +> **Service Information**: The ROCK Admin service runs by default on `http://127.0.0.1:8080`. + +## 5. Run Example Environments + +Now you can run example environments to verify the installation. Ensure the ROCK service is running, then open a new terminal window to execute the following commands: + +```bash +# Ensure virtual environment is activated +source .venv/bin/activate + +# Run sandbox example +python examples/sandbox_demo.py + +# Run GEM protocol example +python examples/sokoban_demo.py +``` + +### 5.1 Example Descriptions + +- **sandbox_demo.py**: Demonstrates how to use ROCK's sandbox SDK to create and manage containerized environments +- **sokoban_demo.py**: Demonstrates how to use ROCK's GEM protocol compatible interface to create reinforcement learning environments + +> **Running Requirements**: Ensure the ROCK Admin service is running, as examples need to communicate with the service. + +## 6. Distributed Environment Configuration (Optional) + +For distributed multi-machine environments, ensure the following configurations are consistent: + +1. All machines use the same root Python interpreter for ROCK and uv Python configurations +2. Docker versions are consistent across all nodes +3. Network configuration allows normal communication between nodes + + +## 7. MacOS Startup + +On macOS, if you need to start Linux image environments, you first need to set the environment variable: + +```bash +export ROCK_WORKER_ENV_TYPE=uv +``` + +During container startup, the corresponding uv environment will be installed. For details, please refer to the `rock/rocklet/local_files/docker_run_with_uv.sh` script. + +> **Note**: Compared to Linux systems, the startup speed on macOS will be slower and more dependent on network conditions. You can adjust the script according to actual conditions.You can find detatils for ROCK_WORKER_ENV_TYPE in [Configuration Guide](../User%20Guides/configuration.md). + +## 8. Starting from Pip Source + +If starting the Admin Server from Pip source, after completing the ROCK installation by referring to [installation](./installation.md), you need to set an additional environment variable: + +```bash +export ROCK_WORKER_ENV_TYPE=pip +``` + +(This startup method will pull and install the latest rocklet from the PyPI source when starting the container environment. The startup speed is relatively slow, so it is only recommended for testing purposes. For production environments, other startup methods are still recommended.) + +## Summary + +Congratulations! You have successfully completed the ROCK quick start guide. You should now be able to: + +- Properly set up the ROCK development environment +- Use uv-managed Python environments +- Start and manage ROCK services +- Run example programs to verify installation +- Configure ROCK in distributed environments (if needed) + +For a deeper understanding of ROCK's additional features, please refer to the following documents: + +## Next Steps + +- [Configuration Guide](../User%20Guides/configuration.md) - Detailed information about ROCK configuration options +- [API Documentation](../References/api.md) - View complete API interfaces +- [Python SDK Documentation](../References/Python%20SDK%20References/python_sdk.md) - Learn how to use the Python SDK for development +- [Installation Guide](./installation.md) - Detailed information about ROCK installation and setup +- [Overview](../overview.md) - Understand ROCK's design philosophy \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/Getting Started/rockroll.md b/docs/versioned_docs/version-1.1.x/Getting Started/rockroll.md new file mode 100644 index 000000000..2465a7733 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/Getting Started/rockroll.md @@ -0,0 +1,194 @@ +--- +sidebar_position: 7 +--- + +# ROCK & ROLL Quick Start Guide + +This guide will walk you through running a reinforcement learning training example based on the Sokoban game, using ROLL (the training framework) and ROCK (the environment management tool). + +## 1. Prerequisites + +Before you begin, please ensure your system has the following dependencies installed. + +### 1.1 System Requirements + +- **OS**: A Linux-based system is recommended (e.g., Ubuntu 20.04+). +- **Hardware**: An NVIDIA GPU with the corresponding drivers is recommended. +- **Docker**: ROCK uses Docker for containerized environment management. +- **uv**: ROCK uses uv for dependency management and virtual environment creation. + +### 1.2 Verify Dependencies & Pre-pull Image + +```bash +# Verify Docker installation +docker --version + +# Verify Docker is running and pre-pull the Sokoban environment image +# This will save time when the training starts. +docker pull rock-n-roll-registry.cn-hangzhou.cr.aliyuncs.com/rock/sokoban-sandbox:latest + +# Verify uv installation +uv --version + +``` + +### 1.3 Initialize the Project + +```bash +# Clone the project repositories +git clone https://github.com/alibaba/ROCK.git +git clone https://github.com/alibaba/ROLL.git + +# Ensure both repositories are in the same parent directory, like this: +# your-workspace/ +# ├── ROCK/ +# └── ROLL/ +``` + + +## 2. Launch the Training Process + +> Note: The following instructions use torch==2.6.0 and vLLM==0.8.4 as an example. + + +### Option 1: Using a Virtual Environment (Recommended) + +#### Why is this method recommended? +- Isolation: A uv virtual environment ensures that project dependencies are isolated from your system, preventing conflicts. +- Fast Startup: ROCK can reuse this virtual environment, significantly speeding up subsequent task initializations. +- Stability & Reproducibility: Dependency management is cleaner and more reliable. + + +```bash +# Navigate to the ROCK directory +cd ROCK + +# Create and activate a Python 3.10 virtual environment (ROLL recommends Python 3.10) +uv venv --python 3.10 --python-preference only-managed +source .venv/bin/activate + +# Install all of ROCK's dependencies using uv +uv sync --all-extras + +# If using Python 3.10, starting Ray may raise a `ValueError: is not a valid Sentinel`. +# This is due to an incompatibility between `ray` and `click` versions 8.3+. +# To fix this, downgrade `click` to a version below 8.3. This issue does not affect Python 3.11. +uv pip install 'click>=8.2,click<8.3' + +# Navigate to the ROLL directory to install its dependencies +cd ../ROLL + +# Install core PyTorch components +uv pip install torch==2.6.0 torchvision==0.21.0 torchaudio==2.6.0 + +# Install transformer-engine. The --no-build-isolation flag prevents errors where torch cannot be found. +uv pip install transformer-engine[pytorch]==2.2.0 --no-build-isolation + +# Install a pre-compiled version of flash-attention matching the specific CUDA and PyTorch versions +uv pip install https://github.com/Dao-AILab/flash-attention/releases/download/v2.7.2.post1/flash_attn-2.7.2.post1+cu12torch2.6cxx11abiFALSE-cp310-cp310-linux_x86_64.whl + +# Install the remaining dependencies +uv pip install -r requirements_torch260_vllm.txt + +# (Optional) Install Tensorboard to check training metrics +uv pip install tensorboard -i $PYPI_MIRROR + +# All set! Launch the training script. +bash examples/agentic_demo/run_agentic_pipeline_sokoban_sandbox_single_node.sh +``` + +### Option 2: Using the System Environment (Alternative) + +For optimal compatibility with this method, we recommend running these commands inside one of ROLL's official base Docker images. These images come pre-installed with matching CUDA, cuDNN, and other foundational libraries. + +> [ROLL's Official Docker Image List](https://alibaba.github.io/ROLL/docs/Getting%20Started/Installation/image_address) + + +#### Warning +This method will install all Python packages directly into your current environment (e.g., the container's base system), which may cause conflicts with system packages or other projects. + +Since ROCK cannot reuse the environment, it may need to reinstall some dependencies each time a task starts, leading to slower startup times that are dependent on network speed. + + +```bash +# Install ROCK's dependencies +cd ROCK +pip install . +pip install ".[admin]" + +# Install ROLL's dependencies +cd ../ROLL +pip install -r requirements_torch260_vllm.txt + +# Crucial: Configure ROCK to use uv as its worker environment manager +export ROCK_WORKER_ENV_TYPE=uv + +# Launch the training script +bash examples/agentic_demo/run_agentic_pipeline_sokoban_sandbox_single_node.sh +``` + +You have now successfully launched the Sokoban reinforcement learning training process. Happy Rock & Roll! + + +## 3. Multi-Node Deployment + +Instead of running everything on a single machine, you can deploy the **ROCK Service** and **ROLL job** on separate machines. This is a common client-server setup where they communicate over the network. + +### 3.1 Deploy the ROCK Service on Machine A + +On a dedicated machine (or container), follow the [ROCK Quick Start Guide](./quickstart.md) to deploy and start the ROCK service. + +> **Important** +> After starting the service, take note of its IP address and port (e.g., `http://192.168.1.10:8000`). You will need this address for the subsequent steps. + +### 3.2 Prepare the ROLL Client on Machine B + +On the other machine where you will run the training task, perform the following steps. + +1. Verify Network Connectivity + +First, use the curl command to check if you can reach the ROCK service on Machine A from Machine B. +```bash +# Replace : with the actual address of your ROCK service +# If successful, you should receive a response like {"message":"hello, ROCK!"} +curl http://: +``` + +2. Prepare the ROLL Environment + +```bash +# Clone the ROLL repository +git clone https://github.com/alibaba/ROLL.git +cd ROLL + +# Install dependencies +pip install -r requirements_torch260_vllm.txt +``` + +3. Configure the ROLL Connection Address + +Modify ROLL's configuration file to point to the remote ROCK service. +- Open the configuration file: examples/agentic_demo/agentic_val_sokoban_sandbox.yaml. +- Find the "SokobanSandbox" section under "env_config". +- Update the base_url value to your ROCK service's address. +```yaml +custom_envs: + SokobanSandbox: + env_config: + # Change the address here to your ROCK service's address + # Example: base_url: 'http://192.168.1.10:8000' + base_url: 'http://:' +``` + +4. Start Training +Once configured, you can start the ROLL training script on Machine B. + +```bash +# This script will now request environments from the ROCK service on Machine A over the network. +bash examples/agentic_demo/run_agentic_pipeline_sokoban_sandbox_multi_nodes.sh +``` + +### Advanced: Distributed ROLL Training + +If you wish to deploy the ROLL training task itself in a distributed manner, you can refer to ROLL's official documentation for distributed deployment. +> [Quick Start: Multi-Node Deployment Guide](https://alibaba.github.io/ROLL/docs/Getting%20Started/Quick%20Start/multi_nodes_quick_start) \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/References/Python SDK References/model-service.md b/docs/versioned_docs/version-1.1.x/References/Python SDK References/model-service.md new file mode 100644 index 000000000..6d23635a2 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/References/Python SDK References/model-service.md @@ -0,0 +1,115 @@ +--- +sidebar_position: 2 +--- + +# Model Service(Experimental) + +The Model Service provided by ROCK is responsible for handling AI model call communications, serving as a communication bridge between agents and training frameworks (such as Roll) or actual LLM inference services. + +## Architecture Overview + +The model service uses the file system as a communication medium, implementing a request-response mechanism between agents and models. When an agent needs to call a model, the request is first written to a log file, then processed by the listening component. When the model generates a response, the result is written back to the log file and read by the waiting agent. + +## CLI Commands + +To use the model service via CLI, ROCK provides a set of CLI commands that can be accessed via `rock model-service` after installing ROCK in the sandbox: + +### start command +Start the model service process +```bash +rock model-service start --type [local|proxy] +``` + +Parameters: +- `--type`: Model service type, optional `local` or `proxy`, defaults to `local` + +### watch-agent command +Monitor the agent process and send a SESSION_END message when the process exits +```bash +rock model-service watch-agent --pid +``` + +Parameters: +- `--pid`: The ID of the agent process to monitor + +### stop command +Stop the model service +```bash +rock model-service stop +``` + +### anti-call-llm command +Anti-call the LLM interface +```bash +rock model-service anti-call-llm --index [--response ] +``` + +Parameters: +- `--index`: Index of the previous LLM call, starting from 0 +- `--response`: Response from the previous LLM call (optional) + +## File Communication Protocol + +The model service uses files for inter-process communication, defining specific marker formats to distinguish requests and responses: + +### Request Format +``` +LLM_REQUEST_START{JSON request data}LLM_REQUEST_END{metadata JSON} +``` + +### Response Format +``` +LLM_RESPONSE_START{JSON response data}LLM_RESPONSE_END{metadata JSON} +``` + +### Session End Marker +``` +SESSION_END +``` + +Metadata contains timestamp and index information to ensure message order and processing. + +## Sandbox Integration + +### ModelServiceConfig +Located in `rock/sdk/sandbox/model_service/base.py`, defines model service configuration in the sandbox: +- Working directory +- Python and model service installation commands +- Session environment variables +- Various command templates + +### ModelService Class +Handles the lifecycle of model services within the sandbox: +- `install()`: Install model service dependencies in the sandbox +- `start()`: Start the model service +- `stop()`: Stop the model service +- `watch_agent()`: Monitor the agent process +- `anti_call_llm()`: Perform anti-call LLM operations + +## Workflow + +1. Agent initiates a model call request +2. Request is formatted and written to a log file +3. Model service listens to the log file and captures new requests +4. Runtime (Roll) processes the request and generates a response +5. Response is written to the log file +6. Model service returns the response to the agent + +## Configuration Options + +### Service Configuration +- `SERVICE_HOST`: Service host address, defaults to "0.0.0.0" +- `SERVICE_PORT`: Service port, defaults to 8080 + +### Log Configuration +- `LOG_FILE`: Log file path used for communication, containing request and response data + +### Polling Configuration +- `POLLING_INTERVAL_SECONDS`: Polling interval, defaults to 0.1 seconds +- `REQUEST_TIMEOUT`: Request timeout, defaults to unlimited + +### Marker Configuration +Defines markers used to distinguish different types of messages in the log file: +- `REQUEST_START_MARKER` / `REQUEST_END_MARKER` +- `RESPONSE_START_MARKER` / `RESPONSE_END_MARKER` +- `SESSION_END_MARKER` \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/References/Python SDK References/python_sdk.md b/docs/versioned_docs/version-1.1.x/References/Python SDK References/python_sdk.md new file mode 100644 index 000000000..5272d7edb --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/References/Python SDK References/python_sdk.md @@ -0,0 +1,265 @@ +--- +sidebar_position: 2 +--- + +# Python SDK Reference + +This guide provides detailed information on how to use the ROCK SDK for development, including sandbox environment management and GEM environment interaction. + +## 1. Overview + +ROCK SDK provides developers with convenient Python interfaces to use ROCK platform features, including sandbox environment management and GEM environment interaction. + +> **Important Note**: Before using the SDK, ensure that the ROCK Admin service is running. You can start it with the following command: +> ```bash +> rock admin start +> ``` + +## 2. Sandbox SDK + +### 2.1 Basic Sandbox Operations + +```python +import asyncio + +from rock.actions import CreateBashSessionRequest +from rock.sdk.sandbox.client import Sandbox +from rock.sdk.sandbox.config import SandboxConfig + +async def run_sandbox(): + """Run sandbox demo with admin server requirement. + + NOTE: This demo requires the admin server to be running for proper execution. + Make sure to start the admin server before running this script. + Default admin server port is 8080. + """ + # Create sandbox configuration + config = SandboxConfig(image="python:3.11", memory="8g", cpus=2.0) + + # Create sandbox instance + sandbox = Sandbox(config) + + # Start sandbox (connects to admin server) + await sandbox.start() + + # Create session in sandbox for command execution + await sandbox.create_session(CreateBashSessionRequest(session="bash-1")) + + # Execute command in sandbox session + result = await sandbox.arun(cmd="echo Hello ROCK", session="bash-1") + print("\n" + "*" * 50 + "\n" + result.output + "\n" + "*" * 50 + "\n") + + # Stop and clean up sandbox resources + await sandbox.stop() + +if __name__ == "__main__": + # Ensure admin server is running before executing + print("IMPORTANT: Make sure the admin server is running before executing this demo!") + print("Start the admin server with: rock admin start") + asyncio.run(run_sandbox()) +``` + +### 2.2 Sandbox Group Management + +```python +from rock.sdk.sandbox.config import SandboxGroupConfig + +# Create sandbox group configuration +config = SandboxGroupConfig( + image="python:3.11", + size=4, # Create 4 sandboxes + start_concurrency=2, # Concurrency level for startup is 2 +) + +# Create and start sandbox group +sandbox_group = SandboxGroup(config) +await sandbox_group.start() + +# Batch operations +for sandbox in sandbox_group.sandbox_list: + await sandbox.run_in_session(Action(session="default", command="echo Hello")) + +# Batch stop +await sandbox_group.stop() +``` + +### 2.3 Configuration Example + +```python +config = SandboxConfig( + image="python:3.11", + auto_clear_seconds=60 * 20, + experiment_id="test", +) +``` + +### 2.4 Sandbox Speedup Configuration + +ROCK provides sandbox network acceleration capabilities, supporting configuration of APT, PIP, and GitHub mirror sources to improve package download speeds in restricted network environments. + +#### Supported Speedup Types + +**APT Mirror Configuration** + +Configure APT package manager mirror sources for faster Debian/Ubuntu package downloads. + +```python +from rock.sdk.sandbox.speedup import SpeedupType + +# Configure APT mirror +await sandbox.network.speedup( + speedup_type=SpeedupType.APT, + speedup_value="http://mirrors.cloud.aliyuncs.com" +) +``` + +**PIP Mirror Configuration** + +Configure Python package index mirrors for faster pip installations. + +```python +# HTTP mirror +await sandbox.network.speedup( + speedup_type=SpeedupType.PIP, + speedup_value="http://mirrors.cloud.aliyuncs.com" +) + +# HTTPS mirror +await sandbox.network.speedup( + speedup_type=SpeedupType.PIP, + speedup_value="https://mirrors.aliyun.com" +) +``` + +**GitHub Acceleration** + +Configure GitHub IP acceleration by adding custom DNS resolution entries. + +```python +await sandbox.network.speedup( + speedup_type=SpeedupType.GITHUB, + speedup_value="11.11.11.11" +) +``` + +#### Complete Example + +```python +from rock.sdk.sandbox.speedup import SpeedupType +from rock.actions import RunMode + +async def setup_sandbox_with_speedup(): + """Create sandbox and configure acceleration""" + config = SandboxConfig(image="python:3.11") + sandbox = Sandbox(config) + + await sandbox.start() + + # Configure acceleration (before installing packages) + await sandbox.network.speedup( + speedup_type=SpeedupType.APT, + speedup_value="http://mirrors.cloud.aliyuncs.com" + ) + + await sandbox.arun(cmd="apt-get update && apt-get install -y git", mode=RunMode.NOHUP) + + await sandbox.network.speedup( + speedup_type=SpeedupType.PIP, + speedup_value="https://mirrors.aliyun.com" + ) + + # Speedup does not automatically install PIP, it only configures mirror sources for acceleration + await sandbox.arun(cmd="pip install numpy", mode=RunMode.NOHUP) + + # GitHub can be accelerated through mirror IP + await sandbox.network.speedup( + speedup_type=SpeedupType.GITHUB, + speedup_value="11.11.11.11" + ) + + return sandbox +``` + +#### Important Notes + +1. **Configuration Order**: Configure speedup before installing packages +2. **HTTPS vs HTTP**: HTTPS mirrors don't require trusted-host configuration for PIP +3. **GitHub IP**: Different regions may require different IPs for optimal performance +4. **Persistence**: Configurations persist within the sandbox lifecycle +5. **Multiple Calls**: Subsequent speedup calls will override previous configurations +6. **PIP Installation**: The speedup feature only configures mirror sources and does not automatically install PIP + +## 3. GEM SDK + +### 3.1 Python SDK Approach + +```python +import random +import rock + +def main(): + """Main function to run the Sokoban demo with admin server requirement. + + NOTE: This demo requires the admin server to be running for proper execution. + Make sure to start the admin server before running this script. + """ + # Create environment using GEM standard interface + # NOTE: This requires the admin server to be running + env_id = "game:Sokoban-v0-easy" + env = rock.make(env_id) + + # Reset environment to initial state + observation, info = env.reset(seed=42) + print( + "\n" + + "=" * 80 + + "\nInitial Observation:\n" + + str(observation) + + "\n\nInitial Info:\n" + + str(info) + + "\n" + + "=" * 80 + + "\n" + ) + + # Run environment loop until termination + step_count = 0 + while True: + # Interactive environment operation with random actions + action = f"\\boxed{{{random.choice(['up', 'left', 'right', 'down'])}}}" + observation, reward, terminated, truncated, info = env.step(action) + + step_count += 1 + print( + "\n" + + "-" * 80 + + f"\nStep {step_count} - Action: {action}\nReward: {reward}\nObservation:\n{observation}\nInfo: {info}\nTerminated: {terminated}, Truncated: {truncated}\n" + + "-" * 80 + + "\n" + ) + + # Check if environment has reached terminal state + if terminated or truncated: + print("\n" + "=" * 80 + "\nEpisode finished!\n" + "=" * 80 + "\n") + break + + # Clean up environment resources + env.close() + +if __name__ == "__main__": + # Ensure admin server is running before executing + print( + "\n" + + "=" * 80 + + "\nIMPORTANT: Make sure the admin server is running before executing this demo!\nStart the admin server with: rock admin start\n" + + "=" * 80 + + "\n" + ) + main() +``` + +## Related Documents +- [Quick Start Guide](../../Getting%20Started/quickstart.md) - Learn how to quickly get started with the ROCK SDK +- [API Documentation](../api.md) - View the underlying API interfaces encapsulated by the SDK +- [Configuration Guide](../../User%20Guides/configuration.md) - Learn about SDK-related configuration options +- [Installation Guide](../../Getting%20Started/installation.md) - Detailed information about ROCK installation and setup \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/References/Python SDK References/runtime-env.md b/docs/versioned_docs/version-1.1.x/References/Python SDK References/runtime-env.md new file mode 100644 index 000000000..cf13506b4 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/References/Python SDK References/runtime-env.md @@ -0,0 +1,111 @@ +# RuntimeEnv SDK Reference + +RuntimeEnv 模块用于在沙箱中管理语言运行时环境(目前提供了 Python / Node.js)。 + +## 快速开始(使用示例) + +```python +from rock.sdk.sandbox import Sandbox +from rock.sdk.sandbox.config import SandboxConfig +from rock.sdk.sandbox.runtime_env import RuntimeEnv, NodeRuntimeEnvConfig + +sandbox_config = SandboxConfig() +sandbox = Sandbox() +await sandbox.start() + +node_runtime_env_config = NodeRuntimeEnvConfig(version="default") +env = await RuntimeEnv.create(sandbox, node_runtime_env_config) + +await env.run("node --version") +``` + +## RuntimeEnv.create + +异步工厂方法,根据配置创建 RuntimeEnv 实例并初始化,自动注册到 `sandbox.runtime_envs`。 + +```python +from rock.sdk.sandbox.runtime_env import RuntimeEnv, NodeRuntimeEnvConfig + +env = await RuntimeEnv.create( + sandbox, + NodeRuntimeEnvConfig(version="22.18.0"), +) + +# 自动注册,可通过 sandbox.runtime_envs[env.runtime_env_id] 访问 +print(env.runtime_env_id in sandbox.runtime_envs) # True +``` + +## wrapped_cmd + +包装命令,将 `bin_dir` 加入 PATH,确保优先使用运行时环境中的可执行文件。 + +```python +# 默认 prepend=True,bin_dir 优先于系统 PATH +wrapped = env.wrapped_cmd("node script.js") +# 返回: bash -c 'export PATH=/tmp/rock-runtime-envs/node/22.18.0/xxx/runtime-env/bin:$PATH && node script.js' + +``` + +## run + +在运行时环境中执行命令。内部基于 `wrapped_cmd` 实现,自动将 `bin_dir` 加入 PATH。 + +```python +await env.run("node script.js") +await env.run("npm install express") + +# 指定超时时间 +await env.run("npm install some-big-package", wait_timeout=1200) +``` + +## PythonRuntimeEnvConfig + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `type` | `Literal["python"]` | `"python"` | 类型标识 | +| `version` | `"3.11" \| "3.12" \| "default"` | `"default"` | Python 版本,默认 3.11 | +| `pip` | `list[str] \| str \| None` | `None` | pip 包列表或 requirements.txt 路径 | +| `pip_index_url` | `str \| None` | 环境变量 | pip 镜像源 | + +## NodeRuntimeEnvConfig + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `type` | `Literal["node"]` | `"node"` | 类型标识 | +| `version` | `"22.18.0" \| "default"` | `"default"` | Node 版本,默认 22.18.0 | +| `npm_registry` | `str \| None` | `None` | npm 镜像源 | + +## 自定义 RuntimeEnv 实现约束 + +自定义 RuntimeEnv 需遵循以下规则: + +1. **定义 `runtime_env_type` 类属性**:作为类型标识符,用于自动注册到 RuntimeEnv 工厂 +2. **重写 `_get_install_cmd()`**:返回安装命令 +3. **安装命令最后必须**:将目录重命名为 `runtime-env` + + +## NodeRuntimeEnv 简化版实现示例 + +```python +from rock.sdk.sandbox.runtime_env import RuntimeEnv, RuntimeEnvConfig +from typing import Literal +from pydantic import Field +from typing_extensions import override + +# Config class: defines configuration type, used by RuntimeEnv.create() for routing +class NodeRuntimeEnvConfig(RuntimeEnvConfig): + type: Literal["node"] = "node" # Must match runtime_env_type + +# RuntimeEnv implementation: defines how to install and run this runtime +class NodeRuntimeEnv(RuntimeEnv): + runtime_env_type = "node" # Auto-registered to RuntimeEnv._REGISTRY + + @override + def _get_install_cmd(self) -> str: + # Download Node binary and extract, rename to runtime-env + return ( + "wget -q -O node.tar.xz https://npmmirror.com/mirrors/node/v22.18.0/node-v22.18.0-linux-x64.tar.xz && " + "tar -xf node.tar.xz && " + "mv node-v22.18.0-linux-x64 runtime-env" + ) +``` diff --git a/docs/versioned_docs/version-1.1.x/References/Python SDK References/sandbox-agent.md b/docs/versioned_docs/version-1.1.x/References/Python SDK References/sandbox-agent.md new file mode 100644 index 000000000..96bb9efb6 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/References/Python SDK References/sandbox-agent.md @@ -0,0 +1,50 @@ +--- +sidebar_position: 3 +--- + +# Sandbox Agent(Experimental) + +Sandbox Agent is a component in the ROCK framework used to run AI agent tasks in an isolated environment, providing a secure and controllable execution environment for agents. Agents can be integrated with Model Service to achieve elegant handling of LLM model calls. + +## Architecture Overview + +Sandbox Agent initializes and executes agent tasks in an isolated sandbox environment, including steps such as installing necessary dependencies and configuring the runtime environment. The agent system supports multiple types of agents, such as SWE-agent and IFlow CLI, each with their specific configurations and implementation approaches. + +Agents can be integrated with Model Service to handle AI model calls during task execution. When an agent needs to query or call an AI model, the Model Service handles model communication in the background, allowing the agent to focus on task execution. + +## Sandbox Agent Initialization Workflow + +1. Create sandbox environment and agent instance +2. Call `init()` method to initialize the agent +3. Create a dedicated bash session in the sandbox +4. Execute pre-startup commands (such as environment configuration) +5. Install necessary dependencies (Python, Node.js, etc.) +6. Install specific agent tools (such as SWE-agent or IFlow CLI) +7. If model service is configured, synchronously initialize the model service + +## Sandbox Agent Execution Workflow + +1. Prepare task running parameters (problem statement, project path, etc.) +2. Call `run()` method to execute the task +3. Prepare configuration files required for running and upload them to the sandbox environment (if needed) +4. Execute Agent +5. If model service is configured, synchronously monitor the Agent process +6. Wait for task completion and return results + +## Model Service Integration Capabilities + +Sandbox Agent supports seamless integration with Model Service, providing a communication bridge for AI model calls. This integration allows agents to interact with Model Service through the file system communication protocol, implementing an asynchronous request-response mechanism. During Agent initialization, the LLM address requested by the Agent can be configured to the address of the model-service server (such as the default http://localhost:8080/v1/chat/completions), thereby leveraging model-service to access the actual inference service. + +The workflow when an agent is integrated with model service: + +### Before Task Starts +1. Call `start_model_service()` to start the model service +2. Call `watch_agent()` to set up monitoring of the agent process + +### When Agent Calls LLM +1. Agent initiates a model call request +2. Request is written to the log file through the file communication protocol +3. Model service listener captures the request +4. Actual AI model returns a response +5. Response is written back through the file communication protocol +6. Agent reads the response and continues execution diff --git a/docs/versioned_docs/version-1.1.x/References/Python SDK References/sandbox.md b/docs/versioned_docs/version-1.1.x/References/Python SDK References/sandbox.md new file mode 100644 index 000000000..8b3096c40 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/References/Python SDK References/sandbox.md @@ -0,0 +1,71 @@ +# Sandbox SDK Reference + +## `arun` + +`arun()` provides two knobs to control how `nohup` output is handled: + +1. **`response_limited_bytes_in_nohup`** *(integer type)* + Caps the number of characters returned from the nohup output file. Useful when you still need to stream some logs back but want an upper bound (default `None` = no cap). + +2. **`ignore_output`** *(bool, default `False`)* + When set to `True`, `arun()` skips reading the nohup output file entirely. The command still runs to completion and writes logs to `/tmp/tmp_.out`, but the SDK immediately returns a lightweight hint telling agents where to fetch the logs later (via `read_file`, download APIs, or custom commands). This fully decouples "execute command" from "inspect logs". The response also includes the **file size** to help users decide whether to download directly or read in chunks. + +```python +from rock.sdk.sandbox.client import Sandbox +from rock.sdk.sandbox.config import SandboxConfig +from rock.sdk.sandbox.request import CreateBashSessionRequest + +config = SandboxConfig( + image=f"{image}", + xrl_authorization=f"{xrl_authorization}", + user_id=f"{user_id}", + cluster=f"{cluster}", +) +sandbox = Sandbox(config) + +session = sandbox.create_session(CreateBashSessionRequest(session="bash-1")) + +# Example 1: limit the returned logs to 1024 characters +resp_limited = asyncio.run( + sandbox.arun( + cmd="cat /tmp/test.txt", + mode="nohup", + session="bash-1", + response_limited_bytes_in_nohup=1024, + ) +) + +# Example 2: skip collecting logs; agent will download/read them later +resp_detached = asyncio.run( + sandbox.arun( + cmd="bash run_long_job.sh", + mode="nohup", + session="bash-1", + ignore_output=True, + ) +) +print(resp_detached.output) +# Command executed in nohup mode without streaming the log content. +# Status: completed +# Output file: /tmp/tmp_xxx.out +# File size: 15.23 MB +# Use Sandbox.read_file(...), download APIs, or run 'cat /tmp/tmp_xxx.out' ... +``` + +## `read_file_by_line_range` + +**Description**: Asynchronously reads file content by line range, with built-in support for automatic chunking and session management. Key features include: +- Automatic chunked reading for large files +- Automatic total line count estimation +- Built-in retry mechanism (3 retries by default) +- Input parameter validation + +### Usage Examples: + +```python +# Read the entire file +response = await read_file_by_line_range("example.txt") + +# Read a specific line range (1-based, inclusive) +response = await read_file_by_line_range("example.txt", start_line=1, end_line=2000) +``` \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/References/api.md b/docs/versioned_docs/version-1.1.x/References/api.md new file mode 100644 index 000000000..d73bf49d6 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/References/api.md @@ -0,0 +1,195 @@ +--- +sidebar_position: 1 +--- + +# API Reference + +This guide provides detailed information about the core API services provided by the ROCK platform, including sandbox environment management and GEM environment interaction. + +## 1. Overview + +The ROCK platform provides two core API services: +- Sandbox API: Sandbox environment management +- GEM API: GEM environment interaction + +All API interfaces follow RESTful design principles and support JSON format data exchange. + +## 2. Sandbox API + +Full lifecycle management functions for sandbox environments: + +### Sandbox Management Interfaces + +1. **Start Sandbox** - Start a sandbox environment + - Create a new sandbox instance + - Support specifying image, resource configuration and other parameters + +2. **Start Sandbox Async** - Asynchronously start a sandbox environment + - Asynchronously create a sandbox instance + - Suitable for scenarios requiring quick response + +3. **Check Sandbox Alive Status** - Check sandbox alive status + - Verify if the sandbox is running normally + +4. **Get Sandbox Statistics** - Get sandbox statistics + - Get resource usage statistics of the sandbox + +5. **Get Sandbox Status** - Get detailed sandbox status + - Get complete status information of the sandbox + +6. **Stop Sandbox** - Stop sandbox environment + - Safely shut down the sandbox instance + +7. **Commit Sandbox** - Commit sandbox as image + - Save current sandbox state as a new image + +### Command Execution Interfaces + +8. **Execute Command** - Execute command in sandbox + - Run specified command directly in the sandbox + +9. **Create Bash Session** - Create Bash session + - Create a persistent Bash session environment + +10. **Run Command in Session** - Run command in session + - Execute command in a created session + +11. **Close Session** - Close session + - Release session resources + +### File Operation Interfaces + +12. **Read File** - Read sandbox file + - Read specified file content from the sandbox + +13. **Write File** - Write sandbox file + - Write file to the sandbox + +14. **Upload File** - Upload file to sandbox + - Upload local file to the sandbox + +## 3. GEM API + +GEM environment interaction functions: + +1. **Make Environment** - Create GEM environment + - Initialize a new GEM environment instance + +2. **Reset Environment** - Reset GEM environment + - Reset GEM environment to initial state + +3. **Step Environment** - Execute GEM environment step + - Execute an action step in the GEM environment + +4. **Close Environment** - Close GEM environment + - Release GEM environment resources + + +## 4. HTTP API Usage Examples + +### 4.1 Sandbox API Examples + +#### Start Sandbox +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/start' \ +-H 'Content-Type: application/json' \ +-d '{ + "image": "python:3.11", + "resources": { + "cpu": "2", + "memory": "8g" + } +}' +``` + +#### Asynchronously Start Sandbox +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/start_async' \ +-H 'Content-Type: application/json' \ +-d '{ + "image": "python:3.11", + "resources": { + "cpu": "2", + "memory": "8g" + } +}' +``` + +#### Execute Command +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/execute' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345", + "command": "ls -la" +}' +``` + +#### Create Session +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/create_session' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345", + "session": "my_session" +}' +``` + +#### Run Command in Session +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/run_in_session' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345", + "session": "my_session", + "command": "python script.py" +}' +``` + +#### Upload File +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/upload' \ +-F 'file=@./local_file.txt' \ +-F 'target_path=./remote_file.txt' \ +-F 'sandbox_id=sandbox-12345' +``` + +#### Stop Sandbox +```bash +curl -X POST 'http://localhost:8080/apis/envs/sandbox/v1/stop' \ +-H 'Content-Type: application/json' \ +-d '{ + "sandbox_id": "sandbox-12345" +}' +``` + +### 4.2 GEM API Examples + +```bash +# Create GEM environment +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/make' \ +-H 'Content-Type: application/json' \ +-d '{"env_id": "game:Sokoban-v0-easy"}' + +# Reset environment +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/reset' \ +-H 'Content-Type: application/json' \ +-d '{"sandbox_id": "sandbox-12345", "seed": 42}' + +# Execute step +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/step' \ +-H 'Content-Type: application/json' \ +-d '{"sandbox_id": "sandbox-12345", "action": "random_action"}' + +# Close environment +curl -X POST 'http://localhost:8080/apis/v1/envs/gem/close' \ +-H 'Content-Type: application/json' \ +-d '{"sandbox_id": "sandbox-12345"}' +``` + +## Related Documents + +- [Quick Start Guide](../Getting%20Started/quickstart.md) - Learn how to quickly get started with ROCK API +- [Python SDK Documentation](./Python%20SDK%20References/python_sdk.md) - Learn how to use the SDK to call APIs +- [Configuration Guide](../User%20Guides/configuration.md) - Learn about API-related configuration options +- [Installation Guide](../Getting%20Started/installation.md) - Detailed information about ROCK installation and setup \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/Release Notes/index.md b/docs/versioned_docs/version-1.1.x/Release Notes/index.md new file mode 100644 index 000000000..d0ac6357f --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/Release Notes/index.md @@ -0,0 +1,5 @@ +--- +sidebar_position: 1 +--- +# Release Notes +* [release v1.0.1](v1.0.1.md) diff --git a/docs/versioned_docs/version-1.1.x/Release Notes/v1.1.0.md b/docs/versioned_docs/version-1.1.x/Release Notes/v1.1.0.md new file mode 100644 index 000000000..580c62a9b --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/Release Notes/v1.1.0.md @@ -0,0 +1,62 @@ +# v1.1.0 + +## Release Date + + +## Overview + +--- + +## SDK + +### New Features + +#### Model Service(Experimental) +**[Model Service References Documentation](../References/Python%20SDK%20References/model-service.md)** + +#### Sandbox Agent(Experimental) +**[Sandbox Agent References Documentation](../References/Python%20SDK%20References/sandbox-agent.md)** + +#### Sandbox Speedup +**[Sandbox Speedup References Documentation](../References/Python%20SDK%20References/python_sdk.md)** + +Provides network optimization and mirror configuration capabilities for sandbox environments: +- Support for one-click APT public mirror configuration +- PIP mirror acceleration with automatic HTTP/HTTPS and trusted-host handling +- GitHub access acceleration via automated Hosts mapping +- Non-intrusive configuration focusing on source optimization without forced installation +- Strategy-based URL parsing and normalization logic + +--- + +### Enhancements + +--- + +### Bug Fixes + +--- + +## Admin + +### New Features + +--- + +### Enhancements + +--- + +### Bug Fixes + +--- + +## Known Issues +- None at this time + +## Contributors +Thanks to all the contributors who made this release possible! + +## Next Steps +- Enhance documentation and tutorials +- Further performance optimizations and bug fixes \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/User Guides/configuration.md b/docs/versioned_docs/version-1.1.x/User Guides/configuration.md new file mode 100644 index 000000000..604256878 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/User Guides/configuration.md @@ -0,0 +1,189 @@ +--- +sidebar_position: 4 +--- + +# Configuration + +This guide provides detailed instructions on how to configure the ROCK environment to meet different usage requirements, including local development, testing, and production deployment. + +## 1. Environment Variable Configuration + +ROCK supports configuring key parameters through environment variables. The main environment variables are as follows: + +```bash +export ROCK_BASE_URL=http://localhost:8080 # ROCK service base URL +export ROCK_LOG_LEVEL=INFO # Log level +export ROCK_LOGGING_PATH=/path/to/logs # Log file path, default None (output to console) +export ROCK_LOGGING_FILE_NAME=rocklet.log # Log file name, default "rocklet.log", can be customized by admin like admin.log +export ROCK_LOGGING_LEVEL=INFO # Log output level, default "INFO" +export ROCK_WORKER_ENV_TYPE=local # Runtime environment type, options: local, docker, uv, pip +``` + +More environment variables can be found in `rock/env_vars.py`. + +### 1.1 Runtime Environments + +ROCK provides multiple different runtime environments to meet the needs of different scenarios, configured through the `ROCK_WORKER_ENV_TYPE` environment variable. Each environment has different deployment requirements, performance characteristics and applicable scenarios. Each environment has its own unique advantages and limitations, and developers can choose the most suitable runtime environment according to their deployment needs. + +#### 1.1.1 Docker Runtime Environment + +The Docker runtime environment is suitable for Docker image environments where dependencies are pre-installed. This environment requires the `/tmp/miniforge/bin/rocklet` executable to be directly available in the deployment environment. + +**Mount Configuration:** +- `/tmp/miniforge` - Contains pre-installed Python environment +- `/tmp/local_files` - Contains local files required for execution + +**Start Command:** +```bash +chmod +x /tmp/local_files/docker_run.sh && /tmp/local_files/docker_run.sh +``` + +**Use Cases:** +- Containerized deployment environments +- Already built custom Docker image containing `rocklet` +- Suitable for production, fast startup + +**Requirements:** +- Requires a custom Docker image containing `/tmp/miniforge/bin/rocklet` executable +- Docker environment support + +#### 1.1.2 Local Runtime Environment + +The local runtime environment directly uses the Python environment and project files of the current deployment. This environment requires the same operating system between the host and container to directly mount the virtual environment and Python interpreter. + +**Mount Configuration:** +- `python_env_path` - Python environment path +- `project_root` - Project root directory +- `.venv` - Virtual environment directory (mounted as `/tmp/miniforge` in container) +- `local_files` - Local files required for execution + +**Start Command:** +```bash +chmod +x /tmp/local_files/docker_run.sh && /tmp/local_files/docker_run.sh +``` + +**Use Cases:** +- Development environments +- Scenarios where host and target container use the same operating system +- Need to quickly reuse existing Python environment + +**Requirements:** +- Same operating system (host/container) +- Direct access to the currently deployed `.venv` virtual environment +- Python interpreter path compatibility + +#### 1.1.3 UV Runtime Environment + +The UV runtime environment only depends on the available ROCK project, but initialization is relatively slow and network requirements are higher. This environment is most suitable for scenarios without preconfigured environments. It rebuilds the rocklet environment from the original project. This is the recommended environment for Mac OS. + +**Mount Configuration:** +- `project_root` - Project root directory (mounted as `/tmp + project_root` in container) +- `local_files` - Local files required for execution + +**Start Command:** +```bash +chmod +x /tmp/local_files/docker_run_with_uv.sh && /tmp/local_files/docker_run_with_uv.sh '' +``` + +**Use Cases:** +- Mac OS +- Cross-OS startup +- Scenarios without preconfigured environment +- No uv management Rock + +**Advantages:** +- No pre-built image required +- Good cross-platform compatibility +- Suitable for development and testing especially + +**Limitations:** +- Initialization is relatively slow +- Higher network requirements +- Longer startup time + +#### 1.1.4 PIP Runtime Environment + +The PIP runtime environment uses pip to install required dependencies in the container. This environment is suitable for quick setup and scenarios where dependencies can be installed in the container. It is the default runtime environment. It does not require pre-built images containing dependencies, and manages Python packages directly through pip. + +**Mount Configuration:** +- `local_files` - Contains local files required for execution + +**Start Command:** +```bash +chmod +x /tmp/local_files/docker_run_with_pip.sh && /tmp/local_files/docker_run_with_pip.sh +``` + +**Use Cases:** +- ROCK installation from PIP source +- Fast testing of ROCK + +**Advantages:** +- Simple deployment setup + +**Limitations:** +- Long dependency installation time +- Requires network access to install dependency packages +- Dependencies need to be installed each time on startup + +#### 1.1.5 Configuration Guide + +Refer to the following selection guide for different use cases: + +| Scenario | Recommended Environment | Reason | +|----------|--------------------------|-------| +| Production environment | Docker Runtime | Fast startup, stable performance | +| Development environment, same OS | Local Runtime | Environment reuse, fast development cycle | +| Mac development | UV Runtime | Best cross-platform compatibility support | +| Cross-platform development | UV Runtime | Avoids environment compatibility issues | +| Fast testing | UV Runtime | Requires no pre-configuration | +| PIP source installation | PIP Runtime | Install dependencies directly with pip | + +These runtime environments are configured through the `ROCK_WORKER_ENV_TYPE` environment variable, which can be set to "local", "docker", "uv" or "pip". + +### 1.2 Logging Configuration + +Regarding logging configuration, ROCK's logging system has the following characteristics: + +- The logging system cannot output to both file and console simultaneously. If `ROCK_LOGGING_PATH` is set, logs will be output to the designated file, otherwise to console. +- `ROCK_LOGGING_LEVEL` is used to control the output log level, while `ROCK_LOG_LEVEL` is used for general log level settings. + +## 2. Distributed Deployment Requirements + +Since ROCK supports distributed deployment, when running on different nodes of a Ray cluster, the following consistency requirements must be met: + +#### Directory Structure Consistency + +On all Ray nodes, the following directory structure must be completely consistent: +- ROCK project repository directory +- `.venv` virtual environment directory +- The base Python directory that `.venv` depends on + + +#### Mounting Requirements + +ROCK's startup depends on mounting the ROCK project and the corresponding base Python environment, requiring consistency in multi-machine environments: + +#### Verifying Distributed Configuration + +Distributed deployment configuration can be verified through the following methods: + +```bash +# Check directory consistency on all nodes +ls -la /path/to/rock +ls -la /path/to/rock/.venv +ls -la $ROCK_PYTHON_ENV_PATH + +# Verify Python environment availability +$ROCK_PYTHON_ENV_PATH/bin/python --version + +# Check environment variable settings on all nodes +echo $ROCK_PYTHON_ENV_PATH +echo $ROCK_PROJECT_ROOT +``` + +## Related Documents + +- [Quick Start Guide](../Getting%20Started/quickstart.md) - Learn how to quickly set up the ROCK environment +- [API Documentation](../References/api.md) - View sandbox-related API interfaces +- [Python SDK Documentation](../References/Python%20SDK%20References/python_sdk.md) - Learn how to use the SDK to configure sandboxes +- [Installation Guide](../Getting%20Started/installation.md) - Detailed information about ROCK installation and setup \ No newline at end of file diff --git a/docs/versioned_docs/version-1.1.x/overview.md b/docs/versioned_docs/version-1.1.x/overview.md new file mode 100644 index 000000000..0c377e8b2 --- /dev/null +++ b/docs/versioned_docs/version-1.1.x/overview.md @@ -0,0 +1,33 @@ +--- +sidebar_position: 1 +--- + +# Overview + +ROCK (Reinforcement Open Construction Kit) is an open-source reinforcement learning environment development framework designed to simplify the development, deployment, and management of reinforcement learning environments. + +## What is ROCK + +ROCK (Reinforcement Open Construction Kit) is an open-source reinforcement learning environment development framework. By using ROCK, developers can quickly develop reinforcement learning environments and integrate with other reinforcement learning training frameworks to implement efficient reinforcement learning training. + +ROCK provides comprehensive sandbox environment management capabilities, supports containerized deployment, and enables rapid creation, execution, and destruction of environments. Additionally, ROCK is compatible with the GEM protocol, providing standardized interfaces for reinforcement learning environments. + +## Core Capabilities of ROCK + +1. **Simplified Development Process**: Simplifies the development, construction, and management of reinforcement learning environments, supporting various open-source reinforcement learning environments +2. **Large-scale Scheduling and Deployment**: Enables large-scale scheduling and deployment of rapid reinforcement learning environments. By supporting the GEM protocol, reinforcement learning environments can be easily accessed +3. **Framework Integration**: Integrates with other reinforcement learning training frameworks to achieve large-scale and scalable reinforcement learning training + +## Value of ROCK + +ROCK provides significant value to different roles of engineers: + +- **Reinforcement Learning Algorithm Engineers**: ROCK simplifies the development process of reinforcement learning environments, allowing engineers to focus on algorithm implementation +- **Reinforcement Learning Application Engineers**: ROCK enables large-scale deployment of rapid reinforcement learning environments, improving application development efficiency + +## Learn More + +- [Quick Start Guide](./Getting%20Started/quickstart.md) - Get started with ROCK quickly +- [Configuration Guide](./User%20Guides/configuration.md) - Detailed information about ROCK configuration options +- [API Documentation](./References/api.md) - View ROCK's API interfaces +- [Python SDK Documentation](./References/Python%20SDK%20References/python_sdk.md) - Learn how to use ROCK's Python SDK \ No newline at end of file diff --git a/docs/versioned_sidebars/version-1.1.x-sidebars.json b/docs/versioned_sidebars/version-1.1.x-sidebars.json new file mode 100644 index 000000000..b475b1153 --- /dev/null +++ b/docs/versioned_sidebars/version-1.1.x-sidebars.json @@ -0,0 +1,64 @@ +{ + "tutorialSidebar": [ + "overview", + { + "type": "category", + "label": "Getting Started", + "link": { + "type": "doc", + "id": "Getting Started/quickstart" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "Getting Started" + } + ] + }, + { + "type": "category", + "label": "User Guides", + "items": [ + { + "type": "autogenerated", + "dirName": "User Guides" + } + ] + }, + { + "type": "category", + "label": "References", + "items": [ + "References/api", + { + "type": "category", + "label": "Python SDK References", + "link": { + "type": "doc", + "id": "References/Python SDK References/python_sdk" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "References/Python SDK References" + } + ] + } + ] + }, + { + "type": "category", + "label": "Release Notes", + "link": { + "type": "doc", + "id": "Release Notes/index" + }, + "items": [ + { + "type": "autogenerated", + "dirName": "Release Notes" + } + ] + } + ] +} diff --git a/docs/versions.json b/docs/versions.json index 69b69959e..febe83b85 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,4 +1,5 @@ [ "1.0.x", + "1.1.x", "0.2.x" ] \ No newline at end of file diff --git a/rock/sdk/sandbox/agent/base.py b/rock/sdk/sandbox/agent/base.py index b527ab53e..8e0131f34 100644 --- a/rock/sdk/sandbox/agent/base.py +++ b/rock/sdk/sandbox/agent/base.py @@ -50,7 +50,7 @@ class DefaultAgent(Agent): - run() - specific execution logic """ - def __init__(self, sandbox: Sandbox, config: DefaultAgentConfig): + def __init__(self, sandbox: Sandbox): warnings.warn( "*** EXPERIMENTAL *** Rock Agent is experimental; API may change. Use with caution.", category=FutureWarning, @@ -60,11 +60,10 @@ def __init__(self, sandbox: Sandbox, config: DefaultAgentConfig): self._sandbox = sandbox self.model_service: ModelService | None = None + self.config: DefaultAgentConfig | None = None + self.agent_session: str | None = None - self.config = config - self.agent_session = self.config.agent_session - - async def install(self): + async def install(self, config: DefaultAgentConfig): """Initialize the agent environment. Common flow: @@ -76,6 +75,9 @@ async def install(self): All installation and post-startup tasks run in parallel with ModelService init. """ + self.config = config + self.agent_session = self.config.agent_session + sandbox_id = self._sandbox.sandbox_id start_time = time.time() diff --git a/rock/sdk/sandbox/agent/iflow_cli.py b/rock/sdk/sandbox/agent/iflow_cli.py index cc5248325..6b6935de7 100644 --- a/rock/sdk/sandbox/agent/iflow_cli.py +++ b/rock/sdk/sandbox/agent/iflow_cli.py @@ -5,17 +5,17 @@ import re import shlex import tempfile -import time from contextlib import contextmanager from typing import TYPE_CHECKING, Any +from pydantic import Field +from typing_extensions import override + from rock import env_vars -from rock.actions import Observation, UploadRequest from rock.logger import init_logger -from rock.sdk.sandbox.agent.base import DefaultAgent -from rock.sdk.sandbox.agent.config import DefaultAgentConfig -from rock.sdk.sandbox.client import Sandbox -from rock.sdk.sandbox.utils import arun_with_retry +from rock.sdk.sandbox.agent.rock_agent import RockAgent, RockAgentConfig +from rock.sdk.sandbox.runtime_env import NodeRuntimeEnvConfig +from rock.sdk.sandbox.utils import with_time_logging if TYPE_CHECKING: from rock.sdk.sandbox.client import Sandbox @@ -23,7 +23,6 @@ logger = init_logger(__name__) -# Default IFlow settings DEFAULT_IFLOW_SETTINGS: dict[str, Any] = { "selectedAuthType": "openai-compatible", "apiKey": "", @@ -55,181 +54,99 @@ } -class IFlowCliConfig(DefaultAgentConfig): - """IFlow CLI Agent Configuration. - - Inherits common agent configuration and adds IFlow-specific settings. - """ - - agent_type: str = "iflow-cli" - - agent_session: str = "iflow-cli-session" - - npm_install_cmd: str = env_vars.ROCK_RTENV_NODE_V22180_INSTALL_CMD - - npm_install_timeout: int = 300 - - iflow_cli_install_cmd: str = env_vars.ROCK_AGENT_IFLOW_CLI_INSTALL_CMD +class IFlowCliConfig(RockAgentConfig): + """IFlow CLI Agent Configuration.""" - iflow_settings: dict[str, Any] = DEFAULT_IFLOW_SETTINGS + agent_type: str = Field(default="iflow-cli") + """OVERRIDE: Type identifier for IFlow CLI agent.""" - iflow_run_cmd: str = "iflow -r {session_id} -p {problem_statement} --yolo > {iflow_log_file} 2>&1" - - iflow_log_file: str = "~/.iflow/session_info.log" + runtime_env_config: NodeRuntimeEnvConfig = Field( + default_factory=lambda: NodeRuntimeEnvConfig( + npm_registry="https://registry.npmmirror.com", + ) + ) + """OVERRIDE: Node runtime environment configuration with npm registry.""" - session_envs: dict[str, str] = { - "LANG": "C.UTF-8", - "LC_ALL": "C.UTF-8", - } + env: dict[str, str] = Field( + default_factory=lambda: { + "LANG": "C.UTF-8", + "LC_ALL": "C.UTF-8", + } + ) + """OVERRIDE: Environment variables for the agent session.""" + iflow_cli_install_cmd: str = Field(default=env_vars.ROCK_AGENT_IFLOW_CLI_INSTALL_CMD) + """Command to install iflow-cli in the sandbox.""" -class IFlowCli(DefaultAgent): - """IFlow CLI Agent implementation. + iflow_settings: dict[str, Any] = Field(default_factory=lambda: DEFAULT_IFLOW_SETTINGS.copy()) + """Default settings for IFlow CLI configuration.""" - Manages the lifecycle of IFlow CLI including installation, configuration, - and execution. Supports session resumption for continuing previous work. - """ + iflow_log_file: str = Field(default="~/.iflow/session_info.log") + """Path to the IFlow session log file.""" - def __init__(self, sandbox: Sandbox, config: IFlowCliConfig): - """Initialize IFlow CLI agent. - Args: - sandbox: Sandbox instance for executing commands - config: IFlowCliConfig instance with agent settings - """ - super().__init__(sandbox, config) +class IFlowCli(RockAgent): + """Specialized IFlowCLI implementation that automatically retrieves session_id from the sandbox + for better checkpoint/resume support. It also supports custom settings files and configurations, + making this implementation more convenient in certain scenarios.""" - self.config: IFlowCliConfig = config + def __init__(self, sandbox: Sandbox): + super().__init__(sandbox) + self.config: IFlowCliConfig | None = None - async def _install(self): + @override + @with_time_logging("Installing IFlow CLI") + async def install(self, config: str | IFlowCliConfig) -> None: """Install IFlow CLI and configure the environment. Steps: - 1. Install npm with retry - 2. Configure npm registry - 3. Install iflow-cli with retry - 4. Create iflow configuration directories - 5. Generate and upload settings configuration file + 1. Initialize Node runtime (npm/node) via super().install() + - npm registry is configured automatically if specified in rt_env_config + 2. Install iflow-cli + 3. Create iflow configuration directories + 4. Upload settings configuration file """ - sandbox_id = self._sandbox.sandbox_id - start_time = time.time() - - logger.info(f"[{sandbox_id}] Starting IFlow CLI installation") + # Step 1: Initialize Node runtime via parent class + await super().install(config) - try: - # Step 1: Install npm - await self._install_npm() + # Step 2: iflow-cli + await self._install_iflow_cli_package() - # Step 2: Configure npm registry - await self._configure_npm_registry() + # Step 3: config dirs + await self._create_iflow_directories() - # Step 3: Install iflow-cli - await self._install_iflow_cli_package() + # Step 4: upload settings + await self._upload_iflow_settings() - # Step 4: Create configuration directories - await self._create_iflow_directories() - - # Step 5: Upload settings configuration - await self._upload_iflow_settings() - - elapsed = time.time() - start_time - logger.info(f"[{sandbox_id}] IFlow CLI installation completed (elapsed: {elapsed:.2f}s)") - - except Exception as e: - elapsed = time.time() - start_time - logger.error( - f"[{sandbox_id}] IFlow CLI installation failed - {str(e)} (elapsed: {elapsed:.2f}s)", - exc_info=True, - ) - raise - - async def _install_npm(self): - """Install npm with Node.js binary.""" + @override + async def _create_agent_run_cmd(self, prompt: str) -> str: + """Create IFlow run command (NOT wrapped by bash -c).""" sandbox_id = self._sandbox.sandbox_id - step_start = time.time() - - self._log_step("Installing npm") - - logger.debug(f"[{sandbox_id}] NPM install command: {self.config.npm_install_cmd[:100]}...") - - await arun_with_retry( - sandbox=self._sandbox, - cmd=f"bash -c {shlex.quote(self.config.npm_install_cmd)}", - session=self.agent_session, - mode="nohup", - wait_timeout=self.config.npm_install_timeout, - error_msg="npm installation failed", - ) - - await self._sandbox.arun( - cmd=( - "mv runtime-env /opt/nodejs && " - "ln -sf /opt/nodejs/bin/npm /usr/local/bin/npm && " - "ln -sf /opt/nodejs/bin/npx /usr/local/bin/npx && " - "ln -sf /opt/nodejs/bin/corepack /usr/local/bin/corepack && " - "ln -sf /opt/nodejs/bin/node /usr/local/bin/node" - ), - session=self.agent_session, - ) - elapsed_step = time.time() - step_start - self._log_step("NPM installation finished", step_name="NPM Install", is_complete=True, elapsed=elapsed_step) - - async def _configure_npm_registry(self): - """Configure npm to use mirror registry for faster downloads.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() + session_id = await self._get_session_id_from_sandbox() + if session_id: + logger.info(f"[{sandbox_id}] Using existing session ID: {session_id}") + else: + logger.info(f"[{sandbox_id}] No previous session found, will start fresh execution") - self._log_step("Configuring npm registry") + iflow_cmd = f'iflow -r "{session_id}" -p {shlex.quote(prompt)} --yolo > {self.config.iflow_log_file} 2>&1' - result = await self._sandbox.arun( - cmd="npm config set registry https://registry.npmmirror.com", - session=self.agent_session, + return self.runtime_env.wrapped_cmd( + f"mkdir -p {self.config.project_path} && cd {self.config.project_path} && {iflow_cmd}" ) - if result.exit_code != 0: - logger.warning(f"[{sandbox_id}] Failed to set npm registry: {result.output}") - else: - logger.debug(f"[{sandbox_id}] Npm registry configured successfully") - - elapsed_step = time.time() - step_start - self._log_step("NPM registry configured", step_name="NPM Registry", is_complete=True, elapsed=elapsed_step) - + @with_time_logging("Installing iflow-cli package") async def _install_iflow_cli_package(self): - """Install iflow-cli package globally.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() - - self._log_step("Installing iflow-cli") + iflow_cli_install_cmd = f"mkdir -p {self.config.agent_installed_dir} && cd {self.config.agent_installed_dir} && {self.config.iflow_cli_install_cmd}" - logger.debug(f"[{sandbox_id}] IFlow CLI install command: {self.config.iflow_cli_install_cmd[:100]}...") - - await arun_with_retry( - sandbox=self._sandbox, - cmd=f"bash -c {shlex.quote(self.config.iflow_cli_install_cmd)}", - session=self.agent_session, - mode="nohup", - wait_timeout=self.config.npm_install_timeout, + # Use node runtime env to run install cmd (wrap is currently bash -c, but uses node_env session) + await self.runtime_env.run( + cmd=iflow_cli_install_cmd, + wait_timeout=self.config.agent_install_timeout, error_msg="iflow-cli installation failed", ) - await self._sandbox.arun( - cmd="ln -s /opt/nodejs/bin/iflow /usr/local/bin/iflow", - session=self.agent_session, - ) - - elapsed_step = time.time() - step_start - self._log_step( - "IFlow CLI installation finished", step_name="IFlow Install", is_complete=True, elapsed=elapsed_step - ) - async def _create_iflow_directories(self): - """Create iflow configuration directories.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() - - self._log_step("Creating iflow settings directories") - result = await self._sandbox.arun( cmd="mkdir -p /root/.iflow && mkdir -p ~/.iflow", session=self.agent_session, @@ -237,50 +154,18 @@ async def _create_iflow_directories(self): if result.exit_code != 0: error_msg = f"Failed to create iflow directories: {result.output}" - logger.error(f"[{sandbox_id}] {error_msg}") + logger.error(f"[{self._sandbox.sandbox_id}] {error_msg}") raise Exception(error_msg) - logger.debug(f"[{sandbox_id}] IFlow settings directories created") - - elapsed_step = time.time() - step_start - self._log_step( - "IFlow configuration directories created", - step_name="Create Directories", - is_complete=True, - elapsed=elapsed_step, - ) - async def _upload_iflow_settings(self): - """Generate and upload iflow-settings.json configuration file.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() - - self._log_step("Generating and uploading iflow settings") - with self._temp_iflow_settings_file() as temp_settings_path: - await self._sandbox.upload( - UploadRequest( - source_path=temp_settings_path, - target_path="/root/.iflow/settings.json", - ) + await self._sandbox.upload_by_path( + file_path=temp_settings_path, + target_path="/root/.iflow/settings.json", ) - logger.debug(f"[{sandbox_id}] Settings uploaded to /root/.iflow/settings.json") - - elapsed_step = time.time() - step_start - self._log_step( - "IFlow settings configuration uploaded", step_name="Upload Settings", is_complete=True, elapsed=elapsed_step - ) @contextmanager def _temp_iflow_settings_file(self): - """Context manager for creating temporary iflow settings file. - - Creates a temporary JSON file with the configured IFlow settings - and ensures cleanup after use. - - Yields: - str: Path to the temporary settings file - """ settings_content = json.dumps(self.config.iflow_settings, indent=2) with tempfile.NamedTemporaryFile(mode="w", suffix="_iflow_settings.json", delete=False) as temp_file: @@ -293,69 +178,41 @@ def _temp_iflow_settings_file(self): os.unlink(temp_settings_path) async def _get_session_id_from_sandbox(self) -> str: - """Retrieve session ID from IFlow log file in sandbox. - - Fetches the last 1000 lines of the log file and extracts the session ID. - Returns empty string if log file is empty, not found, or parsing fails. - - Returns: - Session ID string if found, empty string otherwise - """ sandbox_id = self._sandbox.sandbox_id logger.info(f"[{sandbox_id}] Retrieving session ID from sandbox log file") try: log_file_path = self.config.iflow_log_file - logger.debug(f"[{sandbox_id}] Reading log file: {log_file_path}") - result = await self._sandbox.arun( cmd=f"tail -1000 {log_file_path} 2>/dev/null || echo ''", session=self.agent_session, ) log_content = result.output.strip() - if not log_content: - logger.debug(f"[{sandbox_id}] Log file is empty or not found") return "" - logger.debug(f"[{sandbox_id}] Retrieved log content ({len(log_content)} bytes)") - session_id = self._extract_session_id_from_log(log_content) - return session_id + return self._extract_session_id_from_log(log_content) except Exception as e: logger.error(f"[{sandbox_id}] Error retrieving session ID: {str(e)}") return "" def _extract_session_id_from_log(self, log_content: str) -> str: - """Extract session ID from IFlow log file content. - - Args: - log_content: Content from the log file - - Returns: - Session ID string if found, empty string otherwise - """ sandbox_id = self._sandbox.sandbox_id logger.debug(f"[{sandbox_id}] Attempting to extract session-id from log content") try: json_match = re.search(r"\s*(.*?)\s*", log_content, re.DOTALL) - if not json_match: - logger.debug(f"[{sandbox_id}] No block found in log") return "" json_str = json_match.group(1).strip() data = json.loads(json_str) session_id = data.get("session-id", "") - if session_id: logger.info(f"[{sandbox_id}] Successfully extracted session-id: {session_id}") - return session_id - else: - logger.debug(f"[{sandbox_id}] session-id field not found in Execution Info") - return "" + return session_id or "" except json.JSONDecodeError as e: logger.warning(f"[{sandbox_id}] Failed to parse JSON in Execution Info: {str(e)}") @@ -363,102 +220,3 @@ def _extract_session_id_from_log(self, log_content: str) -> str: except Exception as e: logger.warning(f"[{sandbox_id}] Error extracting session-id: {str(e)}") return "" - - async def run( - self, - problem_statement: str, - project_path: str, - agent_run_timeout: int = 1800, - agent_run_check_interval: int = 30, - ) -> Observation: - """Run IFlow CLI to solve a specified problem. - - Automatically attempts to retrieve the previous session ID from the log file. - If a session ID is found, it will be used to resume the previous execution. - - Args: - problem_statement: Problem statement that IFlow CLI will attempt to solve - project_path: Project path to work on - agent_run_timeout: Agent execution timeout in seconds (default: 1800) - agent_run_check_interval: Interval for checking progress in seconds (default: 30) - - Returns: - Observation: Execution result with exit code and output - """ - sandbox_id = self._sandbox.sandbox_id - start_time = time.time() - - logger.info(f"[{sandbox_id}] Starting IFlow CLI run operation") - logger.debug(f"[{sandbox_id}] Project path: {project_path}, Problem statement: {problem_statement[:100]}...") - - try: - # Step 1: Change to project directory - self._log_step(f"Changing to project directory: {project_path}", step_name="CD Project") - result = await self._sandbox.arun( - cmd=f"cd {project_path}", - session=self.agent_session, - ) - - if result.exit_code != 0: - logger.error(f"[{sandbox_id}] Failed to change directory to {project_path}: {result.output}") - return result - logger.debug(f"[{sandbox_id}] Successfully changed working directory") - - # Step 2: Retrieve session ID from previous execution - logger.info(f"[{sandbox_id}] Attempting to retrieve session ID from previous execution") - session_id = await self._get_session_id_from_sandbox() - if session_id: - logger.info(f"[{sandbox_id}] Using existing session ID: {session_id}") - else: - logger.info(f"[{sandbox_id}] No previous session found, will start fresh execution") - - # Step 3: Execute IFlow CLI command - self._log_step( - f"Running IFlow CLI with timeout {agent_run_timeout}s", - step_name="IFlow Execution", - ) - - iflow_run_cmd = self.config.iflow_run_cmd.format( - session_id=f'"{session_id}"', - problem_statement=shlex.quote(problem_statement), - iflow_log_file=self.config.iflow_log_file, - ) - logger.debug(f"[{sandbox_id}] Formatted IFlow command: {iflow_run_cmd}") - - result = await self._agent_run( - cmd=f"bash -c {shlex.quote(iflow_run_cmd)}", - session=self.agent_session, - wait_timeout=agent_run_timeout, - wait_interval=agent_run_check_interval, - ) - - # Step 4: Log execution outcome - log_file_path = self.config.iflow_log_file - result_log = await self._sandbox.arun( - cmd=f"tail -1000 {log_file_path} 2>/dev/null || echo ''", - session=self.agent_session, - ) - log_content = result_log.output - - elapsed_total = time.time() - start_time - - if result and result.exit_code == 0: - logger.info( - f"[{sandbox_id}] ✓ IFlow-Cli completed successfully " - f"(exit_code: {result.exit_code}, elapsed: {elapsed_total:.2f}s)" - ) - logger.debug(f"[{sandbox_id}] Output: {log_content}") - else: - error_msg = result.failure_reason if result else "No result returned" - logger.error(f"[{sandbox_id}] ✗ IFlow-Cli failed - {error_msg} (elapsed: {elapsed_total:.2f}s)") - logger.error(f"[{sandbox_id}] Output: {log_content}") - - return result - - except Exception as e: - elapsed_total = time.time() - start_time - logger.error( - f"[{sandbox_id}] IFlow CLI execution failed - {str(e)} (elapsed: {elapsed_total:.2f}s)", - exc_info=True, - ) - raise diff --git a/rock/sdk/sandbox/agent/openhands.py b/rock/sdk/sandbox/agent/openhands.py index a4f2feb91..2a6f9de90 100644 --- a/rock/sdk/sandbox/agent/openhands.py +++ b/rock/sdk/sandbox/agent/openhands.py @@ -198,15 +198,23 @@ class Openhands(DefaultAgent): sandbox: Sandbox config: OpenhandsConfig - def __init__(self, sandbox: Sandbox, config: OpenhandsConfig): - """Initialize Agent with sandbox environment and configuration. + def __init__(self, sandbox: Sandbox): + """Initialize Agent with sandbox environment. Args: sandbox: Sandbox instance for isolated agent execution - config: Configuration parameters for agent setup """ - super().__init__(sandbox, config) + super().__init__(sandbox) + + self.agent_prompt_path: str | None = None + + async def install(self, config: OpenhandsConfig) -> None: + """Install and configure Openhands. + Args: + config: Configuration parameters for agent setup + """ + await super().install(config) self.agent_prompt_path = f"{self.config.agent_workdir}/benchmarks/benchmarks/swebench/prompts/custom.j2" async def _install(self): diff --git a/rock/sdk/sandbox/agent/rock_agent.py b/rock/sdk/sandbox/agent/rock_agent.py index 65296521b..cea76209e 100644 --- a/rock/sdk/sandbox/agent/rock_agent.py +++ b/rock/sdk/sandbox/agent/rock_agent.py @@ -35,19 +35,19 @@ class RockAgentConfig(AgentConfig): startup/shutdown commands, and environment configurations. """ - agent_type: str = "default" + agent_type: str = Field(default="default") """Type identifier for the agent.""" - agent_name: str = uuid.uuid4().hex + agent_name: str = Field(default_factory=lambda: uuid.uuid4().hex) """Unique name for the agent instance.""" - version: str = "default" + version: str = Field(default="default") """Version identifier for the agent.""" agent_installed_dir: str = Field(default="/tmp/installed_agent") """Directory where the agent is installed in the sandbox.""" - instance_id: str = Field(default=f"instance-id-{uuid.uuid4().hex}") + instance_id: str = Field(default_factory=lambda: f"instance-id-{uuid.uuid4().hex}") """Unique identifier for this agent instance.""" project_path: str | None = Field(default=None) @@ -57,18 +57,20 @@ class RockAgentConfig(AgentConfig): """Whether to use deploy.working_dir as fallback when project_path is not set. If False and project_path is not set, the command will run without cd to any directory.""" - agent_session: str = Field(default=f"agent-session-{uuid.uuid4().hex}") + agent_session: str = Field(default_factory=lambda: f"agent-session-{uuid.uuid4().hex}") """Session identifier for bash operations.""" env: dict[str, str] = Field(default_factory=dict) """Environment variables for the agent session.""" pre_init_cmds: list[AgentBashCommand] = Field( - default=[AgentBashCommand(**agent_bash_cmd) for agent_bash_cmd in env_vars.ROCK_AGENT_PRE_INIT_BASH_CMD_LIST] + default_factory=lambda: [ + AgentBashCommand(**agent_bash_cmd) for agent_bash_cmd in env_vars.ROCK_AGENT_PRE_INIT_BASH_CMD_LIST + ] ) """Commands to execute before agent initialization.""" - post_init_cmds: list[AgentBashCommand] = Field(default=[]) + post_init_cmds: list[AgentBashCommand] = Field(default_factory=list) """Commands to execute after agent initialization.""" agent_install_timeout: int = Field(default=600, gt=0) @@ -92,7 +94,7 @@ class RockAgentConfig(AgentConfig): runtime_env_config: RuntimeEnvConfigType | None = Field(default_factory=PythonRuntimeEnvConfig) """Runtime environment configuration for the agent.""" - model_service_config: ModelServiceConfig = Field(default_factory=ModelServiceConfig()) + model_service_config: ModelServiceConfig = Field(default_factory=ModelServiceConfig) """ModelService configuration for LLM integration.""" @field_validator("run_cmd") @@ -258,7 +260,7 @@ async def run( - Subclass is responsible for composing the full command content (including `cd ... && ...` if needed). """ - cmd = await self.create_agent_run_cmd(prompt) + cmd = await self._create_agent_run_cmd(prompt) return await self._agent_run( cmd=cmd, session=self.agent_session, @@ -281,12 +283,8 @@ async def _do_init(self): runtime_config = self.config.runtime_env_config - # Create a new RuntimeEnv instance for this agent (uses UUID internally) - self.runtime_env = RuntimeEnv.from_config(self._sandbox, runtime_config) - - # Initialize the runtime (includes installation) - if not self.runtime_env.initialized: - await self.runtime_env.init() + # Create and initialize runtime env (includes installation) + self.runtime_env = await RuntimeEnv.create(self._sandbox, runtime_config) async def _setup_session(self): """Create and configure the bash session for agent operations.""" @@ -413,7 +411,7 @@ async def _init_model_service(self): logger.error(f"[{sandbox_id}] ModelService initialization failed: {str(e)}", exc_info=True) raise - async def create_agent_run_cmd(self, prompt: str) -> str: + async def _create_agent_run_cmd(self, prompt: str) -> str: """Create agent run command. Automatically performs deploy.format() to replace ${working_dir} and ${prompt} placeholders. diff --git a/rock/sdk/sandbox/agent/swe_agent.py b/rock/sdk/sandbox/agent/swe_agent.py index a8edcf4a8..5d0d21742 100644 --- a/rock/sdk/sandbox/agent/swe_agent.py +++ b/rock/sdk/sandbox/agent/swe_agent.py @@ -4,19 +4,17 @@ import os import shlex import tempfile -import time from contextlib import contextmanager -from pathlib import Path -from typing import TYPE_CHECKING, Any, Literal +from typing import TYPE_CHECKING, Any import yaml +from pydantic import Field +from typing_extensions import override -from rock import env_vars -from rock.actions import Observation, UploadRequest from rock.logger import init_logger -from rock.sdk.sandbox.agent.base import DefaultAgent -from rock.sdk.sandbox.agent.config import DefaultAgentConfig -from rock.sdk.sandbox.utils import arun_with_retry +from rock.sdk.sandbox.agent.rock_agent import RockAgent, RockAgentConfig +from rock.sdk.sandbox.runtime_env import PythonRuntimeEnvConfig, RuntimeEnvConfig +from rock.sdk.sandbox.utils import with_time_logging if TYPE_CHECKING: from rock.sdk.sandbox.client import Sandbox @@ -24,9 +22,7 @@ logger = init_logger(__name__) - DEFAULT_SYSTEM_TEMPLATE = "You are a helpful assistant that can interact with a computer to solve tasks." - DEFAULT_INSTANCE_TEMPLATE = """ {{working_dir}} @@ -65,7 +61,6 @@ """ ] -DEFAULT_PARSE_FUNCTION_TYPE = "function_calling" DEFAULT_NEXT_STEP_TEMPLATE = "OBSERVATION:\n{{observation}}" DEFAULT_NEXT_STEP_NO_OUTPUT_TEMPLATE = "Your command ran successfully and did not produce any output." @@ -127,198 +122,123 @@ } -class SweAgentConfig(DefaultAgentConfig): - """Configuration dataclass for SWE-agent initialization and execution. - - Inherits common agent configuration and adds SWE-agent specific settings. - - Attributes: - agent_type: Fixed identifier for this agent type ("swe-agent") - default_run_single_config: Default configuration object for a single run - swe_agent_workdir: Working directory for agent installation and execution - python_install_cmd: Command to install Python environment - swe_agent_install_cmd: Command to clone and install SWE-agent repository - python_install_timeout: Maximum seconds to wait for Python installation - swe_agent_install_timeout: Maximum seconds to wait for SWE-agent installation - agent_run_timeout: Maximum seconds to wait for agent execution completion - agent_run_check_interval: Seconds between status checks during execution - """ - - agent_type: Literal["swe-agent"] = "swe-agent" - - agent_session: str = "swe-agent-session" +class SweAgentConfig(RockAgentConfig): + """SWE-agent configuration.""" - post_startup_bash_cmd_list: list[str] = [] + agent_type: str = "swe-agent" + """OVERRIDE: Type identifier for SWE-agent.""" - swe_agent_workdir: str = "/tmp_sweagent" + runtime_env_config: RuntimeEnvConfig | None = Field(default_factory=lambda: PythonRuntimeEnvConfig(version="3.12")) + """OVERRIDE: Runtime environment configuration.""" - python_install_cmd: str = env_vars.ROCK_RTENV_PYTHON_V31212_INSTALL_CMD - - swe_agent_install_cmd: str = ( - "[ -d SWE-agent ] && rm -rf SWE-agent; " - "git clone https://github.com/SWE-agent/SWE-agent.git && " - "cd SWE-agent && pip install -e . -i https://mirrors.aliyun.com/pypi/simple/" + swe_agent_install_cmd: str = Field( + default=( + "[ -d SWE-agent ] && rm -rf SWE-agent; " + "git clone https://github.com/SWE-agent/SWE-agent.git && " + "cd SWE-agent && pip install -e ." + ) ) + """Command to install SWE-agent in the sandbox.""" - python_install_timeout: int = 300 - - swe_agent_install_timeout: int = 600 + default_run_single_config: dict[str, Any] = Field(default_factory=lambda: DEFAULT_RUN_SINGLE_CONFIG.copy()) + """Default configuration for SWE-agent run_single mode.""" - default_run_single_config: dict[str, Any] = DEFAULT_RUN_SINGLE_CONFIG - session_envs: dict[str, str] = {} +class SweAgent(RockAgent): + """SWE-agent implementation with automatic pre_existing/local configuration. - -class SweAgent(DefaultAgent): - """SWE-agent implementation with integrated ModelService support. - - Manages the complete lifecycle of SWE-agent including environment - initialization, dependency installation, and task execution within - a sandboxed environment. + Automatically configures repo deployment type based on project_path and provides + a default run_single_config for simplified usage. """ - def __init__(self, sandbox: Sandbox, config: SweAgentConfig): - """Initialize SWE-agent with sandbox environment and configuration. + GENERATED_CONFIG_NAME = "generated_config.yaml" + """Filename for the generated SWE-agent configuration.""" - Args: - sandbox: Sandbox instance for isolated agent execution - config: Configuration parameters for agent setup - """ - super().__init__(sandbox, config) + def __init__(self, sandbox: Sandbox): + super().__init__(sandbox) + self.config: SweAgentConfig | None = None - self.config: SweAgentConfig = config + @property + def config_path(self) -> str: + """Path to the generated SWE-agent configuration file in the sandbox.""" + return f"{self.config.agent_installed_dir}/{self.GENERATED_CONFIG_NAME}" - async def _install(self): - """Install SWE-agent and configure the environment. + @override + @with_time_logging("Installing SWE-agent") + async def install(self, config: str | SweAgentConfig) -> None: + """Install SWE-agent after Python runtime environment is ready. - Steps: - 1. Create working directory - 2. Install Python environment - 3. Clone and install SWE-agent repository + This extends the parent install() to perform SWE-agent specific installation: + 1. Clones SWE-agent repository and installs it + 2. Generates and uploads the YAML configuration template """ - sandbox_id = self._sandbox.sandbox_id - start_time = time.time() + await super().install(config) - logger.info(f"[{sandbox_id}] Starting SWE-agent installation") - - try: - # Step 1: Create working directory - await self._create_working_directory() - - # Step 2: Install Python - await self._install_python() - - # Step 3: Install SWE-agent - await self._install_swe_agent_package() - - elapsed = time.time() - start_time - logger.info(f"[{sandbox_id}] SWE-agent installation completed (elapsed: {elapsed:.2f}s)") - - except Exception as e: - elapsed = time.time() - start_time - logger.error( - f"[{sandbox_id}] SWE-agent installation failed - {str(e)} (elapsed: {elapsed:.2f}s)", - exc_info=True, - ) - raise - - async def _create_working_directory(self): - """Create working directory for SWE-agent.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() - - self._log_step(f"Creating working directory: {self.config.swe_agent_workdir}", step_name="Create Workdir") - - mkdir_cmd = f"mkdir -p {self.config.swe_agent_workdir}" - logger.debug(f"[{sandbox_id}] Command: {mkdir_cmd}") - - await self._sandbox.arun( - cmd=mkdir_cmd, - session=self.agent_session, + swe_agent_install_cmd = ( + f"mkdir -p {self.config.agent_installed_dir} " + f"&& cd {self.config.agent_installed_dir} " + f"&& {self.config.swe_agent_install_cmd}" ) - elapsed_step = time.time() - step_start - self._log_step("Working directory created", step_name="Create Workdir", is_complete=True, elapsed=elapsed_step) + await self.runtime_env.run( + cmd=swe_agent_install_cmd, + wait_timeout=self.config.agent_install_timeout, + error_msg="SWE-agent installation failed", + ) - async def _install_python(self): - """Install Python environment.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() + await self._upload_generated_config_template() - self._log_step("Installing Python environment", step_name="Python Install") + @override + async def _create_agent_run_cmd(self, prompt: str) -> str: + """Create the sweagent CLI command for running the agent. - python_install_cmd = f"cd {self.config.swe_agent_workdir} && {self.config.python_install_cmd}" - full_cmd = f"bash -c {shlex.quote(python_install_cmd)}" - logger.debug(f"[{sandbox_id}] Command: {full_cmd}") + Returns a command that invokes sweagent with the generated config + and injects the prompt as the problem_statement. - await arun_with_retry( - sandbox=self._sandbox, - cmd=full_cmd, - session=self.agent_session, - mode="nohup", - wait_timeout=self.config.python_install_timeout, - error_msg="Python installation failed", - ) + Example: + sweagent run --config /installed_agent/generated_config.yaml --problem_statement.text "fix this bug" + """ - elapsed_step = time.time() - step_start - self._log_step( - "Python environment installed", step_name="Python Install", is_complete=True, elapsed=elapsed_step + return ( + f"{self.runtime_env.bin_dir}/sweagent run " + f"--config {self.config_path} " + f"--problem_statement.text {shlex.quote(prompt)}" ) - async def _install_swe_agent_package(self): - """Clone and install SWE-agent repository.""" - sandbox_id = self._sandbox.sandbox_id - step_start = time.time() - - self._log_step("Installing SWE-agent repository", step_name="SWE-agent Install") + @with_time_logging("Uploading SWE-agent config template") + async def _upload_generated_config_template(self) -> None: + """Generate and upload the SWE-agent configuration template. - swe_agent_install_cmd = ( - f"export PATH={self.config.swe_agent_workdir}/runtime-env/bin:$PATH && " - f"cd {self.config.swe_agent_workdir} && " - f"{self.config.swe_agent_install_cmd}" - ) - full_cmd = f"bash -c {shlex.quote(swe_agent_install_cmd)}" - logger.debug(f"[{sandbox_id}] Command: {full_cmd}") - - await arun_with_retry( - sandbox=self._sandbox, - cmd=full_cmd, - session=self.agent_session, - mode="nohup", - wait_timeout=self.config.swe_agent_install_timeout, - error_msg="SWE-agent installation failed", - ) - - elapsed_step = time.time() - step_start - self._log_step( - "SWE-agent repository installed", - step_name="SWE-agent Install", - is_complete=True, - elapsed=elapsed_step, - ) + Creates a temporary YAML config file based on default_run_single_config, + with dynamic values for output_dir and repository paths. + The problem_statement text is injected at runtime via CLI args in _create_agent_run_cmd(). + """ + with self._generated_config_template_context() as local_path: + await self._sandbox.upload_by_path( + file_path=os.path.abspath(local_path), + target_path=self.config_path, + ) @contextmanager - def _config_template_context(self, problem_statement: str, project_path: str, instance_id: str): - """Context manager for temporary config file generation and cleanup. + def _generated_config_template_context(self): + """Context manager to create a temporary SWE-agent YAML config file. - Args: - problem_statement: The problem statement for the task - project_path: Path to the target project - instance_id: The instance identifier for the run + Populates the config template with: + - output_dir: Based on agent_installed_dir and instance_id + - repo: Based on project_path (local path or preexisting) + - problem_statement: Empty (injected at runtime) - Yields: - Path to the temporary config file + Yields the path to the temporary file, which is cleaned up on exit. """ - # Create a copy to avoid modifying the original new_config = copy.deepcopy(self.config.default_run_single_config) - # Set output directory - new_config["output_dir"] = f"/tmp_sweagent/{instance_id}" + # output_dir uses instance_id from config + new_config["output_dir"] = f"{self.config.agent_installed_dir}/{self.config.instance_id}" - # Update project path + # repo/project path uses project_path from config + project_path = self.config.project_path if "env" in new_config and "repo" in new_config["env"]: is_root_level = os.path.dirname(project_path) == "/" - if is_root_level: repo_name = os.path.basename(project_path) new_config["env"]["repo"]["repo_name"] = repo_name @@ -326,147 +246,27 @@ def _config_template_context(self, problem_statement: str, project_path: str, in else: new_config["env"]["repo"]["path"] = project_path new_config["env"]["repo"]["type"] = "local" - # base_commit is set using default value in template - # Update problem statement + # problem_statement will be injected at runtime; keep empty here if "problem_statement" in new_config: - new_config["problem_statement"]["text"] = problem_statement - new_config["problem_statement"]["id"] = instance_id + new_config["problem_statement"]["text"] = "" + new_config["problem_statement"]["id"] = self.config.instance_id - # Create a temporary config file temp_config_file = tempfile.NamedTemporaryFile( mode="w", - suffix=f"_{instance_id}_generated_config.yaml", + suffix="_generated_config.yaml", delete=False, encoding="utf-8", ) - temp_file_path = temp_config_file.name + try: yaml.dump(new_config, temp_config_file, default_flow_style=False, allow_unicode=True) temp_config_file.close() yield temp_file_path - except Exception as e: - raise e finally: try: os.unlink(temp_file_path) logger.debug(f"Temporary config file cleaned up: {temp_file_path}") except OSError as e: logger.warning(f"Failed to clean up temporary config file {temp_file_path}: {str(e)}") - - async def run( - self, - problem_statement: str, - project_path: str, - instance_id: str, - agent_run_timeout: int = 1800, - agent_run_check_interval: int = 30, - ) -> Observation: - """Execute SWE-agent with the specified problem statement and project path. - - This method generates a configuration file from the default template, - uploads it to the sandbox and executes SWE-agent. If ModelService is configured, - it will be started and watch_agent will be called to monitor the agent process. - - Args: - problem_statement: The problem statement for the task - project_path: Path to the target project - instance_id: The instance identifier for the run - agent_run_timeout: Maximum seconds to wait for agent execution (default: 1800) - agent_run_check_interval: Seconds between status checks (default: 30) - - Returns: - Observation: Execution result containing exit code, stdout, and stderr - - Raises: - Exception: If agent execution fails - """ - sandbox_id = self._sandbox.sandbox_id - start_time = time.time() - - logger.info(f"[{sandbox_id}] Starting SWE-agent run operation") - logger.debug( - f"[{sandbox_id}] Project path: {project_path}, Instance ID: {instance_id}, " - f"Problem statement: {problem_statement[:100]}..." - ) - - try: - with self._config_template_context(problem_statement, project_path, instance_id) as generated_config_path: - config_filename = Path(generated_config_path).name - - # Upload configuration file - step_start = time.time() - target_path = f"{self.config.swe_agent_workdir}/{config_filename}" - logger.debug( - f"[{sandbox_id}] UploadRequest(source_path={os.path.abspath(generated_config_path)}, " - f"target_path={target_path})" - ) - - self._log_step("Uploading configuration file", step_name="Upload Config") - - await self._sandbox.upload( - UploadRequest( - source_path=os.path.abspath(generated_config_path), - target_path=target_path, - ) - ) - elapsed_step = time.time() - step_start - self._log_step( - "Configuration file uploaded", - step_name="Upload Config", - is_complete=True, - elapsed=elapsed_step, - ) - - # Execute SWE-agent - step_start = time.time() - self._log_step( - f"Running SWE-agent with timeout {agent_run_timeout}s", - step_name="SWE-agent Run", - ) - - swe_agent_run_cmd = ( - f"cd {self.config.swe_agent_workdir} && " - f"{self.config.swe_agent_workdir}/runtime-env/bin/sweagent run --config {config_filename}" - ) - full_cmd = f"bash -c {shlex.quote(swe_agent_run_cmd)}" - logger.debug( - f"[{sandbox_id}] Command: {full_cmd}\n" - f"Timeout: {agent_run_timeout}s, Check interval: {agent_run_check_interval}s" - ) - - result = await self._agent_run( - cmd=full_cmd, - session=self.agent_session, - wait_timeout=agent_run_timeout, - wait_interval=agent_run_check_interval, - ) - elapsed_step = time.time() - step_start - self._log_step( - "SWE-agent execution completed", - step_name="SWE-agent Run", - is_complete=True, - elapsed=elapsed_step, - ) - - elapsed_total = time.time() - start_time - - if result and result.exit_code == 0: - logger.info( - f"[{sandbox_id}] ✓ SWE-agent completed successfully " - f"(exit_code: {result.exit_code}, elapsed: {elapsed_total:.2f}s)" - ) - else: - error_msg = result.failure_reason if result else "No result returned" - logger.error(f"[{sandbox_id}] ✗ SWE-agent failed - {error_msg} (elapsed: {elapsed_total:.2f}s)") - - return result - - except Exception as e: - elapsed_total = time.time() - start_time - logger.error( - f"[{sandbox_id}] SWE-agent execution failed - {str(e)} (elapsed: {elapsed_total:.2f}s)", - exc_info=True, - ) - raise diff --git a/rock/sdk/sandbox/model_service/base.py b/rock/sdk/sandbox/model_service/base.py index 9de3f83a8..7dbc3906a 100644 --- a/rock/sdk/sandbox/model_service/base.py +++ b/rock/sdk/sandbox/model_service/base.py @@ -106,8 +106,7 @@ async def install(self) -> None: Exception: If any installation step fails. """ # Initialize runtime env (installs Python) - self.runtime_env = RuntimeEnv.from_config(self._sandbox, self.config.runtime_env_config) - await self.runtime_env.init() + self.runtime_env = await RuntimeEnv.create(self._sandbox, self.config.runtime_env_config) await self._create_rock_config() await self._install_model_service() diff --git a/rock/sdk/sandbox/runtime_env/base.py b/rock/sdk/sandbox/runtime_env/base.py index 1a6ff4b47..7650b7df9 100644 --- a/rock/sdk/sandbox/runtime_env/base.py +++ b/rock/sdk/sandbox/runtime_env/base.py @@ -26,9 +26,7 @@ class RuntimeEnv(ABC): session is auto-generated as: runtime-env-{type}-{version}-{runtime_env_id} Usage: - # Factory method to create RuntimeEnv from config - env = RuntimeEnv.from_config(sandbox, config.runtime_env_config) - await env.init() + env = await RuntimeEnv.create(sandbox, config) await env.run("python --version") """ @@ -46,15 +44,18 @@ def __init_subclass__(cls, **kwargs): cls._REGISTRY[cls.runtime_env_type] = cls @classmethod - def from_config(cls, sandbox: Sandbox, runtime_env_config: RuntimeEnvConfig) -> RuntimeEnv: - """Factory method to create RuntimeEnv from config. + async def create(cls, sandbox: Sandbox, runtime_env_config: RuntimeEnvConfig) -> RuntimeEnv: + """Async factory method: create RuntimeEnv from config and initialize it. + + This creates a RuntimeEnv instance of the appropriate type and initializes it. + The instance is automatically registered to sandbox.runtime_envs. Args: sandbox: Sandbox instance runtime_env_config: Runtime environment configuration Returns: - RuntimeEnv instance of the appropriate type, automatically registered to sandbox.runtime_envs + Initialized RuntimeEnv instance of the appropriate type """ runtime_type = runtime_env_config.type runtime_class = cls._REGISTRY.get(runtime_type) @@ -63,6 +64,7 @@ def from_config(cls, sandbox: Sandbox, runtime_env_config: RuntimeEnvConfig) -> runtime_env = runtime_class(sandbox=sandbox, runtime_env_config=runtime_env_config) # Auto-register to sandbox.runtime_envs sandbox.runtime_envs[runtime_env._runtime_env_id] = runtime_env + await runtime_env.init() return runtime_env def __init__( @@ -105,6 +107,11 @@ def workdir(self) -> str: """Working directory for this runtime env instance.""" return self._workdir + @property + def bin_dir(self) -> str: + """Binary directory for this runtime env instance.""" + return f"{self.workdir}/runtime-env/bin" + async def init(self) -> None: """Initialize the runtime environment. @@ -161,11 +168,11 @@ async def run( def wrapped_cmd(self, cmd: str, prepend: bool = True) -> str: """Always wrap with bash -c to ensure it only affects current cmd. Default prepend=True to give current runtime_env highest priority.""" - bin_dir = f"{self._workdir}/runtime-env/bin" + if prepend: - wrapped = f"export PATH={shlex.quote(bin_dir)}:$PATH && {cmd}" + wrapped = f"export PATH={shlex.quote(self.bin_dir)}:$PATH && {cmd}" else: - wrapped = f"export PATH=$PATH:{shlex.quote(bin_dir)} && {cmd}" + wrapped = f"export PATH=$PATH:{shlex.quote(self.bin_dir)} && {cmd}" return f"bash -c {shlex.quote(wrapped)}" async def _ensure_session(self) -> None: diff --git a/tests/integration/sdk/sandbox/agent/swe_agent/test_init.py b/tests/integration/sdk/sandbox/agent/swe_agent/test_init.py index d31f15d79..a6c4f83db 100644 --- a/tests/integration/sdk/sandbox/agent/swe_agent/test_init.py +++ b/tests/integration/sdk/sandbox/agent/swe_agent/test_init.py @@ -1,23 +1,14 @@ -import os - import pytest -from rock import env_vars from rock.actions import Command from rock.logger import init_logger from rock.sdk.sandbox.agent.swe_agent import SweAgent, SweAgentConfig from rock.sdk.sandbox.client import Sandbox -from rock.sdk.sandbox.model_service.base import ModelServiceConfig from tests.integration.conftest import SKIP_IF_NO_DOCKER logger = init_logger(__name__) -def _get_python_install_cmd() -> str: - """Get the Python installation command.""" - return env_vars.ROCK_RTENV_PYTHON_V31114_INSTALL_CMD - - async def _verify_exists(sandbox: Sandbox, directory_path: str, items: set[str]) -> None: """Verify that expected items exist in the directory.""" result = await sandbox.execute(Command(command="ls", cwd=directory_path)) @@ -39,53 +30,13 @@ async def test_swe_agent_initialization(sandbox_instance: Sandbox): swe_agent_config = SweAgentConfig( agent_type="swe-agent", version="unknown", - python_install_cmd=_get_python_install_cmd(), - ) - sandbox_instance.agent = SweAgent(sandbox_instance, swe_agent_config) - - # 2. Initialize the agent - await sandbox_instance.agent.install() - - # 3. Verify agent directory exists in root - agent_dir_name = os.path.basename(swe_agent_config.swe_agent_workdir) - await _verify_exists(sandbox_instance, "/", {agent_dir_name}) - - # 4. Verify agent installation directories - await _verify_exists(sandbox_instance, swe_agent_config.swe_agent_workdir, {"runtime-env", "SWE-agent"}) - - # 5. Verify Python executables - python_bin_path = f"{swe_agent_config.swe_agent_workdir}/runtime-env/bin" - await _verify_exists(sandbox_instance, python_bin_path, {"sweagent"}) - - -@pytest.mark.need_admin -@SKIP_IF_NO_DOCKER -@pytest.mark.asyncio -async def test_swe_agent_with_model_service(sandbox_instance: Sandbox): - """Test SWE-Agent installation with integrated model service.""" - - python_install_cmd = _get_python_install_cmd() - - # 1. Initialize SWE-Agent with model service - model_service_config = ModelServiceConfig() - swe_agent_config = SweAgentConfig( - agent_type="swe-agent", - version="unknown", - python_install_cmd=python_install_cmd, - model_service_config=model_service_config, + project_path="/root", ) - sandbox_instance.agent = SweAgent(sandbox_instance, swe_agent_config) + sandbox_instance.agent = SweAgent(sandbox_instance) # 2. Initialize the agent - await sandbox_instance.agent.install() - - # 3. Verify both agent and model service directories exist in root - agent_dir_name = os.path.basename(swe_agent_config.swe_agent_workdir) - await _verify_exists(sandbox_instance, "/", {agent_dir_name}) + await sandbox_instance.agent.install(swe_agent_config) - # 4. Verify agent installation directories - await _verify_exists(sandbox_instance, swe_agent_config.swe_agent_workdir, {"runtime-env", "SWE-agent"}) + await _verify_exists(sandbox_instance, swe_agent_config.agent_installed_dir, {"SWE-agent"}) - # 5. Verify Python executables - python_bin_path = f"{swe_agent_config.swe_agent_workdir}/runtime-env/bin" - await _verify_exists(sandbox_instance, python_bin_path, {"sweagent"}) + await _verify_exists(sandbox_instance, sandbox_instance.agent.runtime_env.bin_dir, {"sweagent"}) diff --git a/tests/integration/sdk/sandbox/agent/swe_agent/test_run.py b/tests/integration/sdk/sandbox/agent/swe_agent/test_run.py index ac5b1f335..51e227324 100644 --- a/tests/integration/sdk/sandbox/agent/swe_agent/test_run.py +++ b/tests/integration/sdk/sandbox/agent/swe_agent/test_run.py @@ -136,8 +136,8 @@ async def test_swe_agent_run(sandbox_instance: Sandbox) -> None: ) # Initialize and setup the agent - sandbox_instance.agent = SweAgent(sandbox_instance, swe_agent_config) - await sandbox_instance.agent.install() + sandbox_instance.agent = SweAgent(sandbox_instance) + await sandbox_instance.agent.install(swe_agent_config) await sandbox_instance.agent.start_model_service() # Verify health check diff --git a/tests/integration/sdk/sandbox/model_service/test_model_service.py b/tests/integration/sdk/sandbox/model_service/test_model_service.py index f4095c84a..9fffa2472 100644 --- a/tests/integration/sdk/sandbox/model_service/test_model_service.py +++ b/tests/integration/sdk/sandbox/model_service/test_model_service.py @@ -1,6 +1,5 @@ import pytest -from rock import env_vars from rock.actions import Command from rock.logger import init_logger from rock.sdk.sandbox.client import Sandbox @@ -17,8 +16,7 @@ async def test_model_service_install_and_start(sandbox_instance: Sandbox): """Test model service installation and startup flow.""" # 1. Initialize model service - python_install_cmd = env_vars.ROCK_RTENV_PYTHON_V31114_INSTALL_CMD - model_service_config = ModelServiceConfig(python_install_cmd=python_install_cmd) + model_service_config = ModelServiceConfig() sandbox_instance.model_service = ModelService(sandbox_instance, model_service_config) # 2. Install service @@ -38,7 +36,7 @@ async def test_model_service_install_and_start(sandbox_instance: Sandbox): assert "runtime-env" in result.stdout, "Python directory missing" # 5. Verify Python executables - python_bin_path = f"{sandbox_instance.model_service.runtime_env.workdir}/runtime-env/bin" + python_bin_path = sandbox_instance.model_service.runtime_env.bin_dir result = await sandbox_instance.execute(Command(command="ls", cwd=python_bin_path)) logger.info(f"Python bin directory contents: {result.stdout}") assert result.exit_code == 0 diff --git a/tests/integration/sdk/sandbox/test_runtime_env.py b/tests/integration/sdk/sandbox/test_runtime_env.py index 39fc8ab98..34068e20c 100644 --- a/tests/integration/sdk/sandbox/test_runtime_env.py +++ b/tests/integration/sdk/sandbox/test_runtime_env.py @@ -12,8 +12,7 @@ async def test_python_runtime_env(sandbox_instance: Sandbox): """Test Python runtime env basic initialization.""" config = PythonRuntimeEnvConfig(version="3.11") - python_env = RuntimeEnv.from_config(sandbox_instance, config) - await python_env.init() + python_env = await RuntimeEnv.create(sandbox_instance, config) result = await python_env.run("python --version") assert "3.11" in result.output @@ -25,8 +24,7 @@ async def test_python_runtime_env(sandbox_instance: Sandbox): async def test_node_runtime_env(sandbox_instance: Sandbox): """Test Node runtime env basic initialization.""" config = NodeRuntimeEnvConfig(version="22.18.0") - node_env = RuntimeEnv.from_config(sandbox_instance, config) - await node_env.init() + node_env = await RuntimeEnv.create(sandbox_instance, config) result = await node_env.run("node --version") assert "22.18.0" in result.output