feat: Implement dynamic tool registration for RemoteConversation #1129
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
Implements dynamic tool registration for
RemoteConversationto eliminate hardcoded server-side tool registration. This allows clients to use any tool set without server modifications, improving flexibility and scalability.Revised approach: Track module qualnames at registration time in the tool registry and dynamically import modules by qualname on server-side. This eliminates the need for manual mapping and provides a single source of truth.
Fixes #1128
Changes
Client-Side
registry.py: Enhanced tool registry to track module qualnames:_MODULE_QUALNAMESdict to store tool name → module qualname mappingregister_tool()to automatically capture and store module qualname from the factory callable/class/instanceget_tool_module_qualnames()function to retrieve the mappingremote_conversation.py: ModifiedRemoteConversation.__init__()to send tool module qualnames (dict) instead of tool names (list) in the conversation creation payloadServer-Side
models.py: UpdatedStartConversationRequestto accepttool_module_qualnames: dict[str, str]field (defaults to empty dict)conversation_service.py: Modifiedstart_conversation()to dynamically import modules by qualname usingimportlib.import_module(), which triggers tool auto-registrationtool_router.py: Removed hardcodedregister_planning_tools()call (was already removed in previous commit)tool_utils.py: No longer needed as module qualnames are tracked automatically by the registryTests
test_registry_qualnames.py(new): Tests for module qualname tracking in the registryget_tool_module_qualnames()returns a copytest_conversation_router.py: Updated tests to usetool_module_qualnamesdict instead ofregistered_toolslistBenefits
✅ Single Source of Truth: Registry automatically tracks module info when tools register
✅ No Manual Mapping: Module qualnames are captured automatically from the factory
✅ Flexibility: Clients can use any tool set without server changes
✅ Scalability: Works with custom tools automatically
✅ Loose Coupling: Server doesn't need to know about specific tools in advance
✅ Backward Compatibility: Existing code continues to work (tool_module_qualnames defaults to empty dict)
✅ Better DX: Tools "just work" when registered on the client
Architecture
How It Works
Registration Time: When a tool is registered via
register_tool(name, factory):factory.__module__)_MODULE_QUALNAMES[name] = module_qualnameClient Side: When creating a
RemoteConversation:get_tool_module_qualnames()to get the{tool_name: module_qualname}mappingServer Side: When starting a conversation:
tool_module_qualnamesdictimportlib.import_module(qualname)Key Insight
Most tools auto-register when their module is imported (via decorators or module-level code). By tracking module qualnames at registration time, we can:
Testing
All tests pass, including:
Security Considerations
Backward Compatibility
tool_module_qualnamesfield inStartConversationRequestis optional and defaults to empty dictregister_default_tools()intool_router.pyExample Usage
Related