Skip to main content

View source on GitHub

This example demonstrates the correct pattern for customizing agent tools using the OpenHands agent-server API. It configures an agent that has terminal, file_editor, and task_tracker but no browser tool, then verifies the result.

What This Example Shows

  • ✅ How to configure which tools the agent can access, (e.g. use standard tools, but exclude browser tools)
  • ✅ How to verify that the intended tools are present and excluded ones are absent
  • ✅ The complete workflow from sandbox creation to cleanup

The Key Insight: Two APIs

OpenHands Cloud exposes two different APIs, and tool configuration happens on the second one:
  1. Cloud API (https://app.all-hands.dev) — manages the sandbox lifecycle (create, list, delete). Authenticated with your Cloud API key (Authorization: Bearer $OH_API_KEY).
  2. Agent-server API — runs inside each sandbox at the sandbox’s own URL. It controls agent configuration (LLM, tools) and conversation execution. Authenticated with the sandbox’s session API key (X-Session-API-Key: {session_key}).
To customize tools you must talk to the agent-server API. The reliable way to do it is to pass the tool list inline in the agent object when you create the conversation:
Because the agent object defines the whole agent spec (LLM and tools) in a single request, the tools always take effect. The agent-server automatically adds the finish and think tools, so the resulting conversation exposes those two plus the three you asked for. The browser is excluded simply by not being in the list.
Pitfall to avoid: Do not set tools separately via PATCH /api/settings and then create the conversation with an agent object that contains only an llm. Sending an agent object without tools replaces the whole agent spec and drops the tools you configured, leaving the agent with just finish and think. Passing tools inline (as above) avoids this.

How It Works

1. Create a Sandbox via the Cloud API

Then poll GET /api/v1/sandboxes?id={sandbox_id} until status == "RUNNING". A running sandbox gives you:
  • id: the sandbox identifier
  • session_api_key: authentication for the agent-server API
  • exposed_urls: a list of {name, url, port}; the agent-server URL is the entry whose name is AGENT_SERVER

2. Create the Conversation with Tools Inline

3. Run the Conversation

Then poll GET /api/conversations/{conv_id} until execution_status is finished (or error).

4. Verify Tools

The script performs two checks: a) Available tools (from the SystemPromptEvent): confirms every expected tool is present and no browser tool appears.
b) Tools actually used (from ActionEvents): confirms no browser tool was invoked while performing the task.

5. Cleanup

Delete the conversation, then the sandbox.

Run It

Prerequisites

Important: When using the agent-server API directly, you must provide both LLM_API_KEY and LLM_BASE_URL. The agent-server needs to know where to send LLM requests and how to authenticate with the LiteLLM proxy.

Run

The script creates a sandbox, creates a conversation with the custom tools, runs a small task, verifies the tools, and deletes the sandbox. It exits with a non-zero status if verification fails. Expected output:
The exact tool set can vary with your account configuration (for example, MCP integrations may add more tools). What this example guarantees is that the three requested tools are present and no browser tool is included.

Keep Resources for Inspection

This skips cleanup so you can inspect the conversation in the UI.

Available Tools

Common tool names you can include:
  • terminal - Execute bash commands
  • file_editor - Read/write/edit files
  • task_tracker - Track tasks and progress
  • browser_tool_set - Web browser automation (excluded in this example)

Common Issues

”Unauthorized” error

Make sure you’re using the session API key for agent-server calls, not your Cloud API key:

Only finish and think are present

You almost certainly created the conversation with an agent object that contained an llm but no tools. Pass the tools inline in the same request (see “The Key Insight” above).

HTTP 422 when deleting a sandbox

DELETE /api/v1/sandboxes/{id} also requires sandbox_id as a query parameter: DELETE /api/v1/sandboxes/{id}?sandbox_id={id}.

Conversation never finishes

The default timeout is 3 minutes. If your task is complex, inspect the conversation in the UI (https://app.all-hands.dev/conversations/{conv_id}) or fetch its events, and consider a simpler task or a longer timeout.

Architecture Notes

Key insight: Agent customization happens at the agent-server level. The simplest, reliable way to set tools is to pass them inline in the agent object when creating the conversation.

Next Steps

  • See ../custom-agent-with-tool/ for adding completely custom tools.

APIs Used

Key Agent-Server APIs Used

Cloud APIs Used

OpenHands SDK Guide

Agent Settings

Custom Tools