Skip to content

Commit 9366dcc

Browse files
committed
add custom tool calling
1 parent e59e9a3 commit 9366dcc

12 files changed

Lines changed: 1446 additions & 16 deletions

File tree

‎docs/getting-started.md‎

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ This will display:
138138
| `other_backend_kwargs` | `list` | `None` | Configs for additional backends |
139139
| `logger` | `RLMLogger` | `None` | Logger for trajectory tracking |
140140
| `verbose` | `bool` | `False` | Enable console output |
141+
| `custom_tools` | `dict` | `None` | Custom functions/data available in REPL |
142+
| `custom_sub_tools` | `dict` | `None` | Tools for sub-agents (inherits from `custom_tools` if None) |
141143

142144
### The `completion()` Method
143145

@@ -285,6 +287,112 @@ rlm = RLM(
285287

286288
---
287289

290+
## Custom Tools
291+
292+
You can provide custom functions and data that the RLM can use in its REPL environment. This allows you to give the model access to domain-specific tools, APIs, or helper functions.
293+
294+
### Basic Usage
295+
296+
```python
297+
def fetch_weather(city: str) -> str:
298+
"""Fetch weather data for a city."""
299+
# Your API call here
300+
return f"Weather in {city}: Sunny, 72°F"
301+
302+
def calculate_shipping(weight: float, distance: float) -> float:
303+
"""Calculate shipping cost."""
304+
return weight * 0.5 + distance * 0.1
305+
306+
rlm = RLM(
307+
backend="openai",
308+
backend_kwargs={"model_name": "gpt-4o"},
309+
custom_tools={
310+
"fetch_weather": fetch_weather,
311+
"calculate_shipping": calculate_shipping,
312+
"API_KEY": "your-api-key", # Non-callable values become variables
313+
},
314+
)
315+
316+
result = rlm.completion("What's the weather in Tokyo and calculate shipping for 10kg over 500km?")
317+
```
318+
319+
Inside the REPL, the model can now call:
320+
```python
321+
weather = fetch_weather("Tokyo")
322+
cost = calculate_shipping(10, 500)
323+
```
324+
325+
### Tool Descriptions
326+
327+
You can provide descriptions for your tools that will be included in the system prompt, helping the model understand what each tool does:
328+
329+
```python
330+
rlm = RLM(
331+
backend="openai",
332+
backend_kwargs={"model_name": "gpt-4o"},
333+
custom_tools={
334+
# Dict format: {"tool": callable_or_value, "description": "..."}
335+
"fetch_weather": {"tool": fetch_weather, "description": "Fetch current weather data for a city name"},
336+
"calculate_shipping": {"tool": calculate_shipping, "description": "Calculate shipping cost given weight (kg) and distance (km)"},
337+
"API_KEY": {"tool": "your-api-key", "description": "API key for the weather service"},
338+
},
339+
)
340+
```
341+
342+
The descriptions are automatically added to the system prompt:
343+
```
344+
6. Custom tools and data available in the REPL:
345+
- `fetch_weather`: Fetch current weather data for a city name
346+
- `calculate_shipping`: Calculate shipping cost given weight (kg) and distance (km)
347+
- `API_KEY`: API key for the weather service
348+
```
349+
350+
### Custom Tools for Sub-Agents
351+
352+
By default, sub-agents (code using `llm_query()`) inherit the same custom tools. You can customize this:
353+
354+
```python
355+
# Sub-agents get different tools
356+
rlm = RLM(
357+
backend="openai",
358+
backend_kwargs={"model_name": "gpt-4o"},
359+
custom_tools={"main_tool": my_main_function},
360+
custom_sub_tools={"sub_tool": my_sub_function}, # Different tools for sub-agents
361+
)
362+
363+
# Sub-agents get no tools
364+
rlm = RLM(
365+
backend="openai",
366+
backend_kwargs={"model_name": "gpt-4o"},
367+
custom_tools={"main_tool": my_main_function},
368+
custom_sub_tools={}, # Empty dict = no tools for sub-agents
369+
)
370+
```
371+
372+
### Isolated Environments (Modal, Daytona)
373+
374+
For isolated environments, custom tools must be serializable. You can provide:
375+
376+
1. **Code strings** - Python code that defines the function:
377+
```python
378+
custom_tools = {
379+
"helper": '''
380+
def helper(x):
381+
return x * 2
382+
''',
383+
}
384+
```
385+
386+
2. **Serializable data** - JSON-compatible values (strings, numbers, dicts, lists):
387+
```python
388+
custom_tools = {
389+
"CONFIG": {"api_url": "https://api.example.com", "timeout": 30},
390+
"ALLOWED_CITIES": ["Tokyo", "London", "New York"],
391+
}
392+
```
393+
394+
---
395+
288396
## Logging and Debugging
289397

290398
### Enable Logging

‎docs/src/app/environments/page.tsx‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ export default function EnvironmentsPage() {
109109
<code key="4" className="text-sm font-semibold">FINAL_VAR(var_name)</code>,
110110
"Mark a variable as the final answer to return from the RLM"
111111
],
112+
[
113+
<code key="5" className="text-sm font-semibold">custom_tools</code>,
114+
"Any custom functions or data you provide via the custom_tools parameter"
115+
],
112116
]}
113117
/>
114118
</div>
@@ -119,13 +123,60 @@ context = "Your input here"
119123
# Query a sub-LM
120124
result = llm_query("Summarize the context", model="gpt-5-mini")
121125
126+
# Use a custom tool (if provided)
127+
data = fetch_data(context["url"]) # Custom function
128+
122129
# Process the result
123130
summary = process(result)
124131
125132
# Return final answer
126133
FINAL_VAR(summary)`} />
127134
</div>
128135

136+
<div className="my-12">
137+
<h2 className="text-2xl font-bold mb-4">Custom Tools</h2>
138+
139+
<p className="text-muted-foreground mb-6 leading-relaxed">
140+
You can provide custom functions and data that the RLM can use in its REPL environment
141+
via the <code className="px-1.5 py-0.5 rounded bg-muted text-foreground text-sm font-semibold">custom_tools</code> parameter:
142+
</p>
143+
144+
<CodeBlock code={`from rlm import RLM
145+
146+
def fetch_weather(city: str) -> str:
147+
"""Fetch weather data for a city."""
148+
return f"Weather in {city}: Sunny, 72°F"
149+
150+
rlm = RLM(
151+
backend="openai",
152+
backend_kwargs={"model_name": "gpt-4o"},
153+
custom_tools={
154+
# Plain format (no description)
155+
"fetch_weather": fetch_weather,
156+
157+
# Dict format with description (recommended)
158+
"calculate_tip": {"tool": lambda x: x * 0.2, "description": "Calculate 20% tip for a bill amount"},
159+
"API_KEY": {"tool": "your-key", "description": "API key for external services"},
160+
},
161+
)
162+
163+
# The model can now call fetch_weather() in its REPL code`} />
164+
165+
<p className="text-muted-foreground mt-6 leading-relaxed">
166+
<strong className="text-foreground">Tool descriptions:</strong> Use the dict format
167+
<code className="px-1.5 py-0.5 rounded bg-muted text-foreground text-sm font-semibold">{`{"tool": value, "description": "..."}`}</code> to
168+
provide descriptions that help the model understand what each tool does. Descriptions are automatically
169+
included in the system prompt.
170+
</p>
171+
172+
<p className="text-muted-foreground mt-4 leading-relaxed">
173+
<strong className="text-foreground">Sub-agent tools:</strong> By default, sub-agents (code using
174+
<code className="px-1.5 py-0.5 rounded bg-muted text-foreground text-sm font-semibold">llm_query()</code>)
175+
inherit the same custom tools. Use <code className="px-1.5 py-0.5 rounded bg-muted text-foreground text-sm font-semibold">custom_sub_tools</code> to
176+
provide different tools for sub-agents, or pass an empty dict to disable tools for sub-agents.
177+
</p>
178+
</div>
179+
129180
<div className="my-12">
130181
<h2 className="text-2xl font-bold mb-4">Architecture</h2>
131182

0 commit comments

Comments
 (0)