-
Notifications
You must be signed in to change notification settings - Fork 95
feat: Add support for custom tools with remote agent server #1383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Add tool_utils.py with TOOL_MODULE_MAP and register_tools_by_name() for dynamic tool import - Update StartConversationRequest model to accept registered_tools field - Update RemoteConversation to send list of registered tools in payload - Update conversation_service to dynamically register tools from client - Remove hardcoded register_planning_tools() call from tool_router.py - Add comprehensive tests for dynamic tool registration - Maintain backward compatibility for existing code Fixes #1128 Co-authored-by: openhands <openhands@all-hands.dev>
Revised approach: Track module qualnames at registration time and dynamically import modules by qualname on server-side. Changes: - Modified tool registry to track module qualnames when tools are registered - Added _MODULE_QUALNAMES dict to store tool name -> module qualname mapping - Updated register_tool() to capture and store module qualname from factory - Added get_tool_module_qualnames() function to retrieve the mapping - Updated StartConversationRequest model to accept tool_module_qualnames dict - Updated RemoteConversation to send tool module qualnames in conversation payload - Updated conversation_service to dynamically import modules by qualname - Removed hardcoded planning tools registration from tool_router.py - Removed tool_utils.py and manual TOOL_MODULE_MAP (superseded by registry tracking) - Added comprehensive tests for dynamic tool registration This approach provides a single source of truth in the registry and works with any tool without predefined mappings. Fixes #1128 Co-authored-by: openhands <openhands@all-hands.dev>
Resolved conflicts in tests/agent_server/test_conversation_router.py by keeping both sets of tests: - test_start_conversation_with_tool_module_qualnames - test_start_conversation_without_tool_module_qualnames - test_set_conversation_security_analyzer_success - test_set_conversation_security_analyzer_with_none - test_security_analyzer_endpoint_with_malformed_analyzer_data All tests pass successfully. Co-authored-by: openhands <openhands@all-hands.dev>
SDK tests should not import from openhands.tools. Since this test uses GlobTool from openhands.tools, it should be in tests/cross which is for tests that use both SDK and tools packages. This fixes the CI failure where the sdk-tests job checks for and rejects any openhands.tools imports in tests/sdk/. Co-authored-by: openhands <openhands@all-hands.dev>
All tools are now dynamically registered via tool_module_qualnames sent by the client. The server imports tool modules based on the client's registry, eliminating the need for pre-registering default tools at server startup. This change completes the dynamic tool registration implementation by: - Removing the last hardcoded server-side tool registration - Ensuring tools are only registered when a client needs them - Supporting custom and default tools through the same mechanism Co-authored-by: openhands <openhands@all-hands.dev>
This commit fixes multiple issues that prevented the example from running: 1. VSCode Port Conflict: - Added OH_ENABLE_VSCODE=false to server environment to avoid port 8001 conflict - The VSCode service was trying to bind to the same port as the API server 2. Missing API Key Authentication: - Added api_key parameter to ManagedAPIServer class - Set SESSION_API_KEY environment variable when starting the server - Pass api_key to Workspace initialization - Use 'local-test-key' for local testing 3. LLM Configuration: - Changed default model to use litellm_proxy/ prefix - Set default base_url to https://llm-proxy.app.all-hands.dev/ - This allows the example to work with the LiteLLM proxy 4. Simplified Example Flow: - Modified example to demonstrate server connectivity without requiring LLM API calls - Skip agent.run() to avoid needing valid LLM API key - Add try/except for title generation and cost calculation - Example now focuses on showing RemoteConversation setup and basic operations The example now successfully demonstrates: - Starting a managed API server - Creating a RemoteConversation - Sending messages - Retrieving conversation state and events - Proper cleanup Co-authored-by: openhands <openhands@all-hands.dev>
This reverts commit add21d2.
When the agent server restarts and loads persisted conversations from disk, it now dynamically registers the tools by importing their modules based on the stored tool_module_qualnames. This ensures tools are available when resuming conversations, preventing KeyError when the agent tries to use them. The fix adds tool registration logic in the __aenter__() method of ConversationService, which is called during server startup. For each persisted conversation, it: 1. Reads the tool_module_qualnames from stored metadata 2. Imports each module using importlib.import_module() 3. The import triggers tool auto-registration via decorators 4. Logs successful registrations and warnings for failures This complements the existing tool registration for new conversations and ensures tools work correctly in both scenarios. Co-authored-by: openhands <openhands@all-hands.dev>
…ion' into implement-custom-tools-remote-agent
This example demonstrates how to use custom tools with a remote agent server by building a custom Docker image that includes the tool implementation. Features: - Custom ReportBugTool for structured bug data collection - Dockerfile that extends base agent server image with custom tools - Build script for creating custom images - Complete SDK example showing the full workflow - Comprehensive README with usage instructions Implements: #1381 Co-authored-by: openhands <openhands@all-hands.dev>
- Modified Dockerfile to build agent-server from source instead of using pre-built image - This ensures conversation_service.py includes the dynamic tool registration code - Fixed Docker build path for custom_tools directory in .dockerignore - Updated logging to use DEBUG level instead of INFO for tool registration - Successfully tested: custom tools now register correctly on remote agent server Co-authored-by: openhands <openhands@all-hands.dev>
Coverage Report •
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
@OpenHands please review diff from main and try to run the example introduced in this PR and tell me if it is runnable. You may need to install docker and build docker before you start to run it |
|
I'm on it! xingyaoww can track my progress at all-hands.dev |
The Dockerfile copies SDK packages from the repository root (openhands-sdk, openhands-tools, etc.), so the build context must be the repository root, not the example directory. Co-authored-by: openhands <openhands@all-hands.dev>
SummaryI reviewed the diff from main and tested the example introduced in PR #1383. Here are my findings: Is the Example Runnable?Yes, the example is runnable with one bug fix that I made and pushed. Bug Found and FixedThe original Fix applied:
Test ResultsAfter the fix, I successfully:
The LLM authentication error ( Commit PushedI pushed the fix to the PR branch: The PR is now updated at: #1383 |
|
Looks like there are a few issues preventing this PR from being merged!
If you'd like me to help, just leave a comment, like Feel free to include any additional details that might help me get this PR into a better state. You can manage your notification settings |
Summary
This PR implements support for custom tools when using a remote agent server, addressing issue #1381.
Changes
Core Implementation
conversation_service.pyto dynamically import and register custom tools from client'stool_module_qualnamesRemoteConversation.create()to send tool module qualnames to the serverStartConversationRequestto include optionaltool_module_qualnamesfieldExample Implementation
Added comprehensive example under
examples/02_remote_agent_server/05_custom_tool/:ReportBugTool- demonstrates structured data collection pattern (common use case for QA workflows)custom_tool_example.pyshowing end-to-end usagebuild_custom_image.shfor easy Docker image creationTesting
Successfully tested that:
@register_tooldecoratorRelated PRs
Closes
Closes #1381
Co-authored-by: openhands openhands@all-hands.dev
Agent Server images for this PR
• GHCR package: https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server
Variants & Base Images
eclipse-temurin:17-jdknikolaik/python-nodejs:python3.12-nodejs22golang:1.21-bookwormPull (multi-arch manifest)
# Each variant is a multi-arch manifest supporting both amd64 and arm64 docker pull ghcr.io/openhands/agent-server:a5f5726-pythonRun
All tags pushed for this build
About Multi-Architecture Support
a5f5726-python) is a multi-arch manifest supporting both amd64 and arm64a5f5726-python-amd64) are also available if needed