fix: Improve AI tool detection and fallback handling

- Fix Hanzo Node detection to verify chat endpoint actually works
- Skip Hanzo Node if /v1/chat/completions returns 404
- Add proper fallback chain when primary tool fails
- Show helpful error messages and suggest working alternatives
- agent will be used when Hanzo Node isn't functional
This commit is contained in:
2025-09-06 07:51:14 -05:00
parent 02f02aa3b6
commit 8e6f5f2458
5 changed files with 143 additions and 19 deletions
+80
View File
@@ -0,0 +1,80 @@
#!/bin/bash
# Hanzo Package Publishing Script
# Version 0.2.5
set -e
echo "=================================="
echo "Hanzo Package Publishing"
echo "Version: 0.2.5"
echo "=================================="
echo
# Check if we're in the right directory
if [ ! -f "pyproject.toml" ]; then
echo "Error: pyproject.toml not found. Please run from pkg/hanzo directory."
exit 1
fi
# Clean previous builds
echo "Cleaning previous builds..."
rm -rf dist/ build/ *.egg-info 2>/dev/null || true
# Build the package
echo "Building distribution packages..."
python -m build
# Check the build
echo
echo "Build complete. Contents:"
ls -la dist/
# Test the package (optional)
echo
read -p "Do you want to test the package locally before uploading? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Creating test virtual environment..."
python -m venv test_env
source test_env/bin/activate
pip install dist/hanzo-0.2.5-py3-none-any.whl
echo "Testing hanzo command..."
hanzo --version
deactivate
rm -rf test_env
echo "Test successful!"
fi
# Upload to TestPyPI first (optional)
echo
read -p "Do you want to upload to TestPyPI first? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "Uploading to TestPyPI..."
python -m twine upload --repository testpypi dist/*
echo
echo "Package uploaded to TestPyPI."
echo "Test with: pip install --index-url https://test.pypi.org/simple/ hanzo"
echo
read -p "Continue to PyPI? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "Stopping here. Package is on TestPyPI."
exit 0
fi
fi
# Upload to PyPI
echo
echo "Uploading to PyPI..."
echo "You will be prompted for your PyPI credentials or API token."
echo
python -m twine upload dist/*
echo
echo "=================================="
echo "Package published successfully!"
echo "Install with: pip install hanzo"
echo "Current version: 0.2.5"
echo "=================================="
+1 -1
View File
@@ -1,6 +1,6 @@
[project]
name = "hanzo"
version = "0.3.28"
version = "0.3.29"
description = "Hanzo AI - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime"
authors = [
{name = "Hanzo AI", email = "[email protected]"},
+1 -1
View File
@@ -1,6 +1,6 @@
"""Hanzo - Complete AI Infrastructure Platform with CLI, Router, MCP, and Agent Runtime."""
__version__ = "0.3.28"
__version__ = "0.3.29"
__all__ = ["main", "cli", "__version__"]
from .cli import cli, main
@@ -645,8 +645,25 @@ class EnhancedHanzoREPL:
if success:
self.console.print(output)
else:
# Fallback to regular model
self.console.print(f"[yellow]{self.current_tool.display_name} failed, trying cloud model...[/yellow]")
# Show error and try fallback
self.console.print(f"[red]Error: {output}[/red]")
# Try to find next available tool
if self.tool_detector and self.tool_detector.detected_tools:
for fallback_tool in self.tool_detector.detected_tools:
if fallback_tool != self.current_tool:
self.console.print(f"[yellow]Trying {fallback_tool.display_name}...[/yellow]")
success, output = self.tool_detector.execute_with_tool(fallback_tool, message)
if success:
self.console.print(output)
# Suggest switching to working tool
self.console.print(f"\n[dim]Tip: Switch to {fallback_tool.display_name} with /model {fallback_tool.name}[/dim]")
return
else:
self.console.print(f"[red]{fallback_tool.display_name} also failed[/red]")
# Final fallback to cloud model
self.console.print(f"[yellow]Falling back to cloud model...[/yellow]")
await self.execute_command("ask", f"--cloud --model gpt-3.5-turbo {message}")
else:
# Use regular model through hanzo ask
+42 -15
View File
@@ -170,22 +170,46 @@ class ToolDetector:
try:
response = httpx.get(tool.api_endpoint, timeout=1.0)
if response.status_code == 200:
tool.detected = True
tool.version = "Running"
# Special handling for Hanzo services
# For Hanzo Node, verify it can actually handle chat completions
if tool.name == "hanzod":
# Check if models are loaded
try:
models_response = httpx.get("http://localhost:8000/models", timeout=1.0)
if models_response.status_code == 200:
models = models_response.json()
if models:
tool.version = f"Running ({len(models)} models)"
# Check if the chat completions endpoint works
test_response = httpx.post(
"http://localhost:8000/v1/chat/completions",
json={
"messages": [{"role": "user", "content": "test"}],
"model": "test",
"max_tokens": 1
},
timeout=2.0
)
# Only mark as detected if we get a valid response or specific error
# 404 means the endpoint doesn't exist
if test_response.status_code == 404:
return False
tool.detected = True
tool.version = "Running (Local AI)"
# Try to get model info
try:
models_response = httpx.get("http://localhost:8000/v1/models", timeout=1.0)
if models_response.status_code == 200:
models = models_response.json().get("data", [])
if models:
tool.version = f"Running ({len(models)} models)"
except:
pass
return True
except:
pass
return True
# If chat endpoint doesn't work, node isn't useful
return False
else:
# For other services, just check health endpoint
tool.detected = True
tool.version = "Running"
return True
except:
pass
@@ -318,12 +342,13 @@ class ToolDetector:
try:
# Special handling for Hanzo services
if tool.name == "hanzod":
# Use the local API directly
# Use the local API directly with correct endpoint
try:
response = httpx.post(
"http://localhost:8000/chat/completions",
"http://localhost:8000/v1/chat/completions",
json={
"messages": [{"role": "user", "content": prompt}],
"model": "default", # Use default model
"stream": False
},
timeout=30.0
@@ -331,6 +356,8 @@ class ToolDetector:
if response.status_code == 200:
result = response.json()
return True, result.get("choices", [{}])[0].get("message", {}).get("content", "")
else:
return False, f"Hanzo Node returned {response.status_code}: {response.text}"
except Exception as e:
return False, f"Hanzo Node error: {e}"