Skip to content

Commit 3e3e1bc

Browse files
authored
Merge branch 'main' into sid/add-e2b-sandboxes
2 parents 43693ec + a8874d4 commit 3e3e1bc

24 files changed

Lines changed: 3081 additions & 1302 deletions

‎AGENTS.md‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ uv pip install -e .
1818

1919
# For Modal sandbox support
2020
uv pip install -e ".[modal]"
21+
22+
# For Prime sandbox support
23+
uv pip install -e ".[prime]"
2124
```
2225

2326
## General Guidelines

‎Makefile‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
.PHONY: help install install-dev install-modal run-all \
2+
quickstart docker-repl lm-repl modal-repl \
3+
lint format test check
4+
5+
help:
6+
@echo "RLM Examples Makefile"
7+
@echo ""
8+
@echo "Usage:"
9+
@echo " make install - Install base dependencies with uv"
10+
@echo " make install-dev - Install dev dependencies with uv"
11+
@echo " make install-modal - Install modal dependencies with uv"
12+
@echo " make run-all - Run all examples (requires all deps and API keys)"
13+
@echo ""
14+
@echo "Examples:"
15+
@echo " make quickstart - Run quickstart.py (needs OPENAI_API_KEY)"
16+
@echo " make docker-repl - Run docker_repl_example.py (needs Docker)"
17+
@echo " make lm-repl - Run lm_in_repl.py (needs PORTKEY_API_KEY)"
18+
@echo " make modal-repl - Run modal_repl_example.py (needs Modal)"
19+
@echo ""
20+
@echo "Development:"
21+
@echo " make lint - Run ruff linter"
22+
@echo " make format - Run ruff formatter"
23+
@echo " make test - Run tests"
24+
@echo " make check - Run lint + format + tests"
25+
26+
install:
27+
uv sync
28+
29+
install-dev:
30+
uv sync --group dev --group test
31+
32+
install-modal:
33+
uv pip install -e ".[modal]"
34+
35+
run-all: quickstart docker-repl lm-repl modal-repl
36+
37+
quickstart: install
38+
uv run python -m examples.quickstart
39+
40+
docker-repl: install
41+
uv run python -m examples.docker_repl_example
42+
43+
lm-repl: install
44+
uv run python -m examples.lm_in_repl
45+
46+
modal-repl: install-modal
47+
uv run python -m examples.modal_repl_example
48+
49+
lint: install-dev
50+
uv run ruff check .
51+
52+
format: install-dev
53+
uv run ruff format .
54+
55+
test: install-dev
56+
uv run pytest
57+
58+
check: lint format test

‎README.md‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,14 @@ uv init && uv venv --python 3.12 # change version as needed
5353
uv pip install -e .
5454
```
5555

56-
To run a quick test, the following will run an RLM query with the OpenAI client using your environment variable `OPENAI_API_KEY` (feel free to change this). This will generate console output as well as a log which you can use with the visualizer to explore the trajectories.
56+
This project includes a `Makefile` to simplify common tasks.
57+
58+
- `make install`: Install base dependencies.
59+
- `make check`: Run linter, formatter, and tests.
60+
61+
To run a quick test, the following will run an RLM query with the OpenAI client using your environment variable `OPENAI_API_KEY` (feel free to change this). This will generate console output as well as a log which you can use with the visualizer to explore the trajectories.
5762
```bash
58-
uv run examples/quickstart.py
63+
make quickstart
5964
```
6065

6166
The default RLM client uses a REPL environment that runs on the host process through Python `exec` calls. It uses the same virtual environment as the host process (i.e. it will have access to the same dependencies), but with some limitations in its available global modules. As an example, we can call RLM completions using GPT-5-nano:
@@ -98,14 +103,13 @@ modal setup # authenticate account
98103
```
99104

100105
#### Prime Intellect Sandboxes <img src="https://github.com/PrimeIntellect-ai.png" alt="Prime Intellect" height="20" style="vertical-align: middle;"/>
101-
> [!WARNING]
102-
> **Prime Intellect Sandboxes** are currently a beta feature. See the [documentation](https://docs.primeintellect.ai/sandboxes/overview) for more information.
106+
> [!NOTE]
107+
> **Prime Intellect Sandboxes** are currently a beta feature. See the [documentation](https://docs.primeintellect.ai/sandboxes/overview) for more information. We noticed slow runtimes when using these sandboxes, which is currently an open issue.
103108
104-
> [!IMPORTANT]
105-
> **Prime Intellect Sandboxes are not yet implemented** in `rlm`. This feature is not available at the moment until we patch some bugs.
106109

107-
See [Prime CLI setup instructions](https://docs.primeintellect.ai/inference/overview) for getting setup. You will need to set your CLI key.
110+
To use [Prime Sandboxes](https://docs.primeintellect.ai/sandboxes/sdk), install the SDK and set your API key:
108111
```bash
112+
uv pip install -e ".[prime]"
109113
export PRIME_API_KEY=...
110114
```
111115

‎examples/lm_in_prime_repl.py‎

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""
2+
Example: Using llm_query() from within a Prime Intellect Sandbox.
3+
4+
This demonstrates the LM Handler + PrimeREPL integration where code
5+
running in a cloud sandbox can query the LLM via the HTTP broker pattern.
6+
"""
7+
8+
import os
9+
10+
from dotenv import load_dotenv
11+
12+
from rlm.clients.portkey import PortkeyClient
13+
from rlm.core.lm_handler import LMHandler
14+
from rlm.environments.prime_repl import PrimeREPL
15+
16+
load_dotenv()
17+
18+
setup_code = """
19+
secret = "1424424"
20+
"""
21+
22+
context_payload = """
23+
This is a test context. It should print out, revealing the magic number to be 4.
24+
"""
25+
26+
code = """
27+
response = llm_query("What is 2 + 2? Reply with just the number.")
28+
print(response)
29+
print(type(response))
30+
print(context)
31+
print("Secret from setup code: ", secret)
32+
"""
33+
34+
35+
def main():
36+
api_key = os.environ.get("PORTKEY_API_KEY")
37+
if not api_key:
38+
print("Error: PORTKEY_API_KEY not set")
39+
return
40+
print(f"PORTKEY_API_KEY: {api_key[:8]}...")
41+
42+
client = PortkeyClient(api_key=api_key, model_name="@openai/gpt-5-nano")
43+
print("Created Portkey client with model: @openai/gpt-5-nano")
44+
45+
# Start LM Handler
46+
with LMHandler(client=client) as handler:
47+
print(f"LM Handler started at {handler.address}")
48+
49+
# Create Prime REPL with handler connection
50+
print("\nCreating Prime sandbox...")
51+
with PrimeREPL(
52+
name="rlm-lm-demo",
53+
docker_image="python:3.11-slim",
54+
timeout_minutes=30,
55+
lm_handler_address=handler.address,
56+
context_payload=context_payload,
57+
setup_code=setup_code,
58+
) as repl:
59+
print(f"PrimeREPL created, sandbox ID: {repl.sandbox_id}")
60+
print(f"Broker URL: {repl.broker_url}\n")
61+
62+
# Run code that uses llm_query
63+
print(f"Executing: {code}")
64+
65+
result = repl.execute_code(code)
66+
67+
print(f"stdout: {result.stdout!r}")
68+
print(f"stderr: {result.stderr!r}")
69+
print(f"response variable: {result.locals.get('response')!r}")
70+
print(f"locals: {result.locals!r}")
71+
print(f"execution time: {result.execution_time:.3f}s")
72+
print(f"rlm_calls made: {len(result.rlm_calls)}")
73+
74+
75+
if __name__ == "__main__":
76+
main()

‎examples/prime_repl_example.py‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
3+
from dotenv import load_dotenv
4+
5+
from rlm import RLM
6+
from rlm.logger import RLMLogger
7+
8+
load_dotenv()
9+
10+
logger = RLMLogger(log_dir="./logs")
11+
12+
rlm = RLM(
13+
backend="openai",
14+
backend_kwargs={
15+
"api_key": os.getenv("OPENAI_API_KEY"),
16+
"model_name": "gpt-5-nano",
17+
},
18+
environment="prime",
19+
environment_kwargs={
20+
"name": "rlm-prime-demo",
21+
"docker_image": "python:3.11-slim",
22+
"timeout_minutes": 30,
23+
},
24+
max_depth=1,
25+
logger=logger,
26+
verbose=True,
27+
)
28+
29+
result = rlm.completion("Using your code, solve 2^(2^(2^(2))). Show your work in Python.")
30+
print(result.response)

‎pyproject.toml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ dependencies = [
2121
[project.optional-dependencies]
2222
modal = ["modal>=0.73.0", "dill>=0.3.7"]
2323
e2b = ["e2b-code-interpreter>=0.0.11", "dill>=0.3.7"]
24+
prime = ["prime-sandboxes>=0.2.0", "dill>=0.3.7"]
2425

2526
[build-system]
2627
requires = ["setuptools>=61.0"]

‎rlm/clients/__init__.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ def get_client(
3636

3737
backend_kwargs.setdefault("base_url", "https://openrouter.ai/api/v1")
3838
return OpenAIClient(**backend_kwargs)
39+
elif backend == "vercel":
40+
from rlm.clients.openai import OpenAIClient
41+
42+
backend_kwargs.setdefault("base_url", "https://ai-gateway.vercel.sh/v1")
43+
return OpenAIClient(**backend_kwargs)
3944
elif backend == "litellm":
4045
from rlm.clients.litellm import LiteLLMClient
4146

@@ -54,5 +59,5 @@ def get_client(
5459
return AzureOpenAIClient(**backend_kwargs)
5560
else:
5661
raise ValueError(
57-
f"Unknown backend: {backend}. Supported backends: ['openai', 'vllm', 'portkey', 'openrouter', 'litellm', 'anthropic', 'azure_openai', 'gemini']"
62+
f"Unknown backend: {backend}. Supported backends: ['openai', 'vllm', 'portkey', 'openrouter', 'litellm', 'anthropic', 'azure_openai', 'gemini', 'vercel']"
5863
)

‎rlm/clients/azure_openai.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ def __init__(
3939
if api_version is None:
4040
api_version = os.getenv("AZURE_OPENAI_API_VERSION", "2024-02-01")
4141

42+
if azure_deployment is None:
43+
azure_deployment = os.getenv("AZURE_OPENAI_DEPLOYMENT")
44+
4245
if azure_endpoint is None:
4346
raise ValueError(
4447
"azure_endpoint is required for Azure OpenAI client. "

‎rlm/clients/openai.py‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
# Load API keys from environment variables
1414
DEFAULT_OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
1515
DEFAULT_OPENROUTER_API_KEY = os.getenv("OPENROUTER_API_KEY")
16+
DEFAULT_VERCEL_API_KEY = os.getenv("AI_GATEWAY_API_KEY")
1617
DEFAULT_PRIME_INTELLECT_BASE_URL = "https://api.pinference.ai/api/v1/"
1718

1819

@@ -35,6 +36,8 @@ def __init__(
3536
api_key = DEFAULT_OPENAI_API_KEY
3637
elif base_url == "https://openrouter.ai/api/v1":
3738
api_key = DEFAULT_OPENROUTER_API_KEY
39+
elif base_url == "https://ai-gateway.vercel.sh/v1":
40+
api_key = DEFAULT_VERCEL_API_KEY
3841

3942
# For vLLM, set base_url to local vLLM server address.
4043
self.client = openai.OpenAI(api_key=api_key, base_url=base_url)
@@ -84,7 +87,7 @@ async def acompletion(
8487
raise ValueError("Model name is required for OpenAI client.")
8588

8689
extra_body = {}
87-
if self.base_url == DEFAULT_PRIME_INTELLECT_BASE_URL:
90+
if self.client.base_url == DEFAULT_PRIME_INTELLECT_BASE_URL:
8891
extra_body["usage"] = {"include": True}
8992

9093
response = await self.async_client.chat.completions.create(

0 commit comments

Comments
 (0)