mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-27 04:20:09 +00:00
Introduces hanzo-tools-* namespace packages for independent tool installation: Core packages: - hanzo-tools-core: BaseTool, ToolRegistry, PermissionManager - hanzo-tools-filesystem: read, write, edit, tree, find, search, ast (7 tools) - hanzo-tools-shell: dag, ps, zsh, shell, npx, uvx, open (7 tools) AI/Agent packages: - hanzo-tools-agent: critic, iching, review, network, CLI agents (12 tools) - hanzo-tools-memory: recall/create/update/delete memories, facts, KB (9 tools) - hanzo-tools-reasoning: think, critic (2 tools) Editor/Dev packages: - hanzo-tools-lsp: Language Server Protocol tool (1 tool) - hanzo-tools-refactor: rename, extract, inline, move, change_signature (1 tool) - hanzo-tools-database: SQL + graph database tools (8 tools) - hanzo-tools-editor: neovim integration (3 tools) - hanzo-tools-jupyter: notebook read/edit (1 tool) - hanzo-tools-browser: Playwright browser automation (1 tool) - hanzo-tools-todo: unified todo management (1 tool) Key improvements: - All subprocess.run calls have timeout protection - All tool .call() methods are async - Namespace package pattern for mix-and-match installation - Entry point discovery via hanzo.tools - No blocking imports (all < 2s) Also updates hanzo-mcp: - Browser tool integration - Tool install/registry for dynamic tool management - Auto-background timeout reduced to 60s
110 lines
3.1 KiB
Python
110 lines
3.1 KiB
Python
"""Tool adapters for converting between MCP tools and OpenAI tools.
|
|
|
|
This module handles conversion between MCP tool formats and OpenAI function
|
|
formats, making MCP tools available to the OpenAI API, and processing tool inputs
|
|
and outputs for agent execution.
|
|
"""
|
|
|
|
# Import litellm with warnings suppressed
|
|
import warnings
|
|
|
|
from openai.types import FunctionParameters
|
|
from openai.types.chat import ChatCompletionToolParam
|
|
|
|
with warnings.catch_warnings():
|
|
warnings.simplefilter("ignore", DeprecationWarning)
|
|
|
|
from hanzo_tools.core import BaseTool
|
|
|
|
|
|
def convert_tools_to_openai_functions(
|
|
tools: list[BaseTool],
|
|
) -> list[ChatCompletionToolParam]:
|
|
"""Convert MCP tools to OpenAI function format.
|
|
|
|
Args:
|
|
tools: List of MCP tools
|
|
|
|
Returns:
|
|
List of tools formatted for OpenAI API
|
|
"""
|
|
openai_tools: list[ChatCompletionToolParam] = []
|
|
for tool in tools:
|
|
openai_tool: ChatCompletionToolParam = {
|
|
"type": "function",
|
|
"function": {
|
|
"name": tool.name,
|
|
"description": tool.description,
|
|
"parameters": convert_tool_parameters(tool),
|
|
},
|
|
}
|
|
openai_tools.append(openai_tool)
|
|
return openai_tools
|
|
|
|
|
|
def convert_tool_parameters(tool: BaseTool) -> FunctionParameters:
|
|
"""Convert tool parameters to OpenAI format.
|
|
|
|
Args:
|
|
tool: MCP tool
|
|
|
|
Returns:
|
|
Parameter schema in OpenAI format
|
|
"""
|
|
# Start with a copy of the parameters
|
|
params = tool.parameters.copy()
|
|
|
|
# Ensure the schema has the right format for OpenAI
|
|
if "properties" not in params:
|
|
params["properties"] = {}
|
|
|
|
if "type" not in params:
|
|
params["type"] = "object"
|
|
|
|
if "required" not in params:
|
|
params["required"] = tool.required
|
|
|
|
return params
|
|
|
|
|
|
def supports_parallel_function_calling(model: str) -> bool:
|
|
"""Check if a model supports parallel function calling.
|
|
|
|
Args:
|
|
model: Model identifier in LiteLLM format (e.g., "openai/gpt-4-turbo-preview")
|
|
|
|
Returns:
|
|
True if the model supports parallel function calling, False otherwise
|
|
"""
|
|
# Since litellm doesn't have this function, we'll implement a simple check
|
|
# based on known models that support parallel function calling
|
|
parallel_capable_models = {
|
|
# OpenAI models that support parallel function calling
|
|
"gpt-4-turbo",
|
|
"gpt-4-turbo-preview",
|
|
"gpt-4-turbo-2024-04-09",
|
|
"gpt-4o",
|
|
"gpt-4o-mini",
|
|
"gpt-4o-2024-05-13",
|
|
"gpt-4o-2024-08-06",
|
|
"gpt-3.5-turbo",
|
|
"gpt-3.5-turbo-0125",
|
|
"gpt-3.5-turbo-1106",
|
|
# Anthropic models with tool support
|
|
"claude-3-opus",
|
|
"claude-3-sonnet",
|
|
"claude-3-haiku",
|
|
"claude-3-5-sonnet",
|
|
"claude-3-5-sonnet-20241022",
|
|
}
|
|
|
|
# Extract model name without provider prefix
|
|
model_name = model.split("/")[-1] if "/" in model else model
|
|
|
|
# Check if the base model name matches any known parallel-capable models
|
|
for capable_model in parallel_capable_models:
|
|
if model_name.startswith(capable_model):
|
|
return True
|
|
|
|
return False
|