mirror of
https://github.com/hanzoai/python-sdk.git
synced 2026-10-23 20:23:00 +00:00
rebrand: rename litellm module to llm — complete purge
All imports, test files, docs, and config references updated. import litellm → import llm across entire codebase.
This commit is contained in:
@@ -120,7 +120,7 @@ jobs:
|
||||
# Run all working tests with strict mode
|
||||
# Note: Some async tests require specific pytest-asyncio configuration
|
||||
# The core test suite validates CI requirements
|
||||
python -m pytest tests/test_agent_tools_ci.py tests/test_litellm_warnings.py \
|
||||
python -m pytest tests/test_agent_tools_ci.py tests/test_llm_warnings.py \
|
||||
-v \
|
||||
--strict-markers \
|
||||
--tb=short \
|
||||
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
cd pkg/hanzo-mcp
|
||||
source .venv/bin/activate
|
||||
# Run specific working tests, excluding the failing stdio_server test
|
||||
python -m pytest tests/test_agent_tools_ci.py tests/test_litellm_warnings.py -v
|
||||
python -m pytest tests/test_agent_tools_ci.py tests/test_llm_warnings.py -v
|
||||
python -m pytest tests/test_hanzo_mcp_simple.py::test_cli_help tests/test_hanzo_mcp_simple.py::test_cli_version tests/test_hanzo_mcp_simple.py::test_import_tools -v
|
||||
echo "✓ Test Summary: 15 tests passed (13 passed + 2 skipped), 100% success rate"
|
||||
|
||||
|
||||
+1
-1
@@ -116,7 +116,7 @@ hanzo-aci includes these dependencies:
|
||||
|
||||
- **numpy, pandas, scipy** - Data processing
|
||||
- **networkx** - Graph analysis
|
||||
- **litellm** - LLM integration
|
||||
- **llm** - LLM integration
|
||||
- **gitpython** - Git operations
|
||||
- **tree-sitter** - AST parsing
|
||||
- **grep-ast** - Code search
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# LLM Tools
|
||||
|
||||
Unified LLM interface via LiteLLM.
|
||||
Unified LLM interface via LLM.
|
||||
|
||||
→ **Full documentation: [../../tools/llm-tools.md](../../tools/llm-tools.md)**
|
||||
|
||||
|
||||
+1
-1
@@ -150,7 +150,7 @@ pip install hanzo-mcp[tools-all]
|
||||
|
||||
# Or specific tools
|
||||
pip install hanzo-mcp[browser] # Playwright
|
||||
pip install hanzo-mcp[llm] # LiteLLM
|
||||
pip install hanzo-mcp[llm] # LLM
|
||||
```
|
||||
|
||||
### Logs and Debugging
|
||||
|
||||
@@ -8,7 +8,7 @@ Unified LLM interface with multi-model consensus. Access 100+ models through a s
|
||||
pip install hanzo-tools-llm[full]
|
||||
```
|
||||
|
||||
Note: This package requires `litellm` which is a heavy dependency. It's disabled by default in hanzo-mcp.
|
||||
Note: This package requires `llm` which is a heavy dependency. It's disabled by default in hanzo-mcp.
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -173,7 +173,7 @@ llm(action="test", model="gpt-4")
|
||||
|
||||
## Supported Providers
|
||||
|
||||
The LLM tool uses [LiteLLM](https://github.com/BerriAI/litellm) to support 100+ models:
|
||||
The LLM tool uses [LLM](https://github.com/BerriAI/llm) to support 100+ models:
|
||||
|
||||
| Provider | Models | API Key Env |
|
||||
|----------|--------|-------------|
|
||||
@@ -317,5 +317,5 @@ Configure model aliases in `~/.hanzo/llm/aliases.json`:
|
||||
1. **Set appropriate temperature** - Low for factual, high for creative
|
||||
2. **Use system prompts** - Provide context for better responses
|
||||
3. **Validate JSON output** - Even with json_mode, validate responses
|
||||
4. **Handle rate limits** - LiteLLM handles retries automatically
|
||||
4. **Handle rate limits** - LLM handles retries automatically
|
||||
5. **Monitor costs** - Different models have different pricing
|
||||
|
||||
@@ -15,7 +15,7 @@ except Exception: # pragma: no cover
|
||||
import os
|
||||
import warnings
|
||||
|
||||
# Suppress litellm deprecation warnings about event loop
|
||||
# Suppress llm deprecation warnings about event loop
|
||||
warnings.filterwarnings(
|
||||
"ignore", message="There is no current event loop", category=DeprecationWarning
|
||||
)
|
||||
|
||||
@@ -156,7 +156,7 @@ Examples:
|
||||
agent_group = parser.add_argument_group("Agent Tool Configuration")
|
||||
agent_group.add_argument(
|
||||
"--agent-model",
|
||||
help="Model name in LiteLLM format (e.g., 'openai/gpt-4o', 'anthropic/claude-3-sonnet')",
|
||||
help="Model name in LLM format (e.g., 'openai/gpt-4o', 'anthropic/claude-3-sonnet')",
|
||||
)
|
||||
agent_group.add_argument(
|
||||
"--agent-max-tokens",
|
||||
|
||||
@@ -20,7 +20,7 @@ if TYPE_CHECKING:
|
||||
from mcp.server import FastMCP
|
||||
|
||||
|
||||
# Suppress litellm deprecation warnings about event loop
|
||||
# Suppress llm deprecation warnings about event loop
|
||||
warnings.filterwarnings(
|
||||
"ignore", message="There is no current event loop", category=DeprecationWarning
|
||||
)
|
||||
@@ -146,7 +146,7 @@ class HanzoMCPServer:
|
||||
project_paths: list of project paths to generate prompts for
|
||||
project_dir: single project directory (added to allowed_paths and project_paths)
|
||||
mcp_instance: Optional FastMCP instance for testing
|
||||
agent_model: Optional model name for agent tool in LiteLLM format
|
||||
agent_model: Optional model name for agent tool in LLM format
|
||||
agent_max_tokens: Optional maximum tokens for agent responses
|
||||
agent_api_key: Optional API key for the LLM provider
|
||||
agent_base_url: Optional base URL for the LLM provider API endpoint
|
||||
|
||||
@@ -46,7 +46,7 @@ def register_all_tools(
|
||||
Args:
|
||||
mcp_server: The FastMCP server instance
|
||||
permission_manager: Permission manager for access control
|
||||
agent_model: Optional model name for agent tool in LiteLLM format
|
||||
agent_model: Optional model name for agent tool in LLM format
|
||||
agent_max_tokens: Optional maximum tokens for agent responses
|
||||
agent_api_key: Optional API key for the LLM provider
|
||||
agent_base_url: Optional base URL for the LLM provider API endpoint
|
||||
|
||||
@@ -11,7 +11,7 @@ from hanzo_mcp.tools.common.mode import (
|
||||
|
||||
# Essential system tools that are ALWAYS enabled regardless of mode
|
||||
# These are core infrastructure tools that should never be disabled
|
||||
# NOTE: llm and consensus are NOT essential (heavy litellm dependency)
|
||||
# NOTE: llm and consensus are NOT essential (heavy llm dependency)
|
||||
ESSENTIAL_SYSTEM_TOOLS: Set[str] = {
|
||||
# Reasoning (lightweight)
|
||||
"think", # Structured thinking
|
||||
@@ -30,10 +30,10 @@ ESSENTIAL_SYSTEM_TOOLS: Set[str] = {
|
||||
}
|
||||
|
||||
# Heavy tools that are disabled by default (opt-in)
|
||||
# These require large dependencies like litellm
|
||||
# These require large dependencies like llm
|
||||
HEAVY_TOOLS: Set[str] = {
|
||||
"llm", # Requires litellm (~100MB+ deps)
|
||||
"consensus", # Requires litellm
|
||||
"llm", # Requires llm (~100MB+ deps)
|
||||
"consensus", # Requires llm
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class PersonalityRegistry:
|
||||
|
||||
|
||||
# Essential tools that are always available in every mode
|
||||
# NOTE: llm/consensus are NOT essential (heavy litellm dependency - opt-in only)
|
||||
# NOTE: llm/consensus are NOT essential (heavy llm dependency - opt-in only)
|
||||
ESSENTIAL_TOOLS = [
|
||||
# File operations
|
||||
"read",
|
||||
@@ -124,11 +124,11 @@ ESSENTIAL_TOOLS = [
|
||||
"tool",
|
||||
]
|
||||
|
||||
# Heavy tools (require large dependencies like litellm)
|
||||
# Heavy tools (require large dependencies like llm)
|
||||
# These are opt-in only, not included by default
|
||||
HEAVY_TOOLS = [
|
||||
"llm", # Requires litellm (~100MB deps)
|
||||
"consensus", # Requires litellm
|
||||
"llm", # Requires llm (~100MB deps)
|
||||
"consensus", # Requires llm
|
||||
]
|
||||
|
||||
# Common tool sets for reuse
|
||||
|
||||
@@ -174,7 +174,7 @@ module = [
|
||||
"bashlex.*",
|
||||
"grep_ast.*",
|
||||
"libtmux.*",
|
||||
"litellm.*",
|
||||
"llm.*",
|
||||
"nbformat.*",
|
||||
"ffind.*",
|
||||
"fastmcp.*",
|
||||
|
||||
@@ -235,12 +235,12 @@ def mock_memory_service():
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_litellm():
|
||||
"""Create a mock litellm module."""
|
||||
def mock_llm():
|
||||
"""Create a mock llm module."""
|
||||
from test_utils import MockServiceHelper
|
||||
|
||||
with pytest.mock.patch("hanzo_tools.agent.agent_tool.litellm") as mock:
|
||||
mock.completion = MockServiceHelper.mock_litellm_completion()
|
||||
with pytest.mock.patch("hanzo_tools.agent.agent_tool.llm") as mock:
|
||||
mock.completion = MockServiceHelper.mock_llm_completion()
|
||||
yield mock
|
||||
|
||||
|
||||
|
||||
+8
-8
@@ -1,4 +1,4 @@
|
||||
"""E2E integration tests for LiteLLM providers.
|
||||
"""E2E integration tests for LLM providers.
|
||||
|
||||
These tests require real API keys and make actual API calls.
|
||||
Only run in CI with proper secrets configured.
|
||||
@@ -6,7 +6,7 @@ Only run in CI with proper secrets configured.
|
||||
|
||||
import os
|
||||
|
||||
import litellm
|
||||
import llm
|
||||
import pytest
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@ import pytest
|
||||
reason="OPENAI_API_KEY environment variable not set",
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_litellm_openai_provider_integration():
|
||||
"""Integration test: LiteLLM with real OpenAI provider."""
|
||||
async def test_llm_openai_provider_integration():
|
||||
"""Integration test: LLM with real OpenAI provider."""
|
||||
messages = [{"role": "user", "content": "Hello, how are you?"}]
|
||||
|
||||
try:
|
||||
response = litellm.completion(
|
||||
response = llm.completion(
|
||||
model="openai/gpt-3.5-turbo",
|
||||
messages=messages,
|
||||
)
|
||||
@@ -34,12 +34,12 @@ async def test_litellm_openai_provider_integration():
|
||||
reason="ANTHROPIC_API_KEY environment variable not set",
|
||||
)
|
||||
@pytest.mark.asyncio
|
||||
async def test_litellm_anthropic_provider_integration():
|
||||
"""Integration test: LiteLLM with real Anthropic provider."""
|
||||
async def test_llm_anthropic_provider_integration():
|
||||
"""Integration test: LLM with real Anthropic provider."""
|
||||
messages = [{"role": "user", "content": "Hello, how are you?"}]
|
||||
|
||||
try:
|
||||
response = litellm.completion(
|
||||
response = llm.completion(
|
||||
model="anthropic/claude-3-haiku-20240307",
|
||||
messages=messages,
|
||||
)
|
||||
@@ -153,8 +153,8 @@ class TestAgentTool:
|
||||
tool_ctx.error.assert_called_once()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_call_with_litellm_error(self, tool_helper, agent_tool, mcp_context):
|
||||
"""Test agent tool call when litellm raises an error."""
|
||||
async def test_call_with_llm_error(self, tool_helper, agent_tool, mcp_context):
|
||||
"""Test agent tool call when llm raises an error."""
|
||||
# Mock the tool context
|
||||
tool_ctx = MagicMock()
|
||||
tool_ctx.error = AsyncMock()
|
||||
|
||||
+12
-12
@@ -1,6 +1,6 @@
|
||||
"""Test LiteLLM with different providers."""
|
||||
"""Test LLM with different providers."""
|
||||
|
||||
import litellm
|
||||
import llm
|
||||
import pytest
|
||||
from hanzo_tools.agent.tool_adapter import convert_tools_to_openai_functions
|
||||
|
||||
@@ -69,8 +69,8 @@ def test_convert_echo_tool_to_openai_functions(echo_tool):
|
||||
assert "parameters" in openai_functions[0]["function"]
|
||||
|
||||
|
||||
def test_litellm_openai_provider_mocked():
|
||||
"""Test LiteLLM with OpenAI provider using mocks."""
|
||||
def test_llm_openai_provider_mocked():
|
||||
"""Test LLM with OpenAI provider using mocks."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
messages = [{"role": "user", "content": "Hello, how are you?"}]
|
||||
@@ -86,9 +86,9 @@ def test_litellm_openai_provider_mocked():
|
||||
mock_response.choices = [mock_choice]
|
||||
|
||||
with patch.object(
|
||||
litellm, "completion", return_value=mock_response
|
||||
llm, "completion", return_value=mock_response
|
||||
) as mock_completion:
|
||||
response = litellm.completion(
|
||||
response = llm.completion(
|
||||
model="openai/gpt-3.5-turbo",
|
||||
messages=messages,
|
||||
)
|
||||
@@ -100,8 +100,8 @@ def test_litellm_openai_provider_mocked():
|
||||
)
|
||||
|
||||
|
||||
def test_litellm_anthropic_provider_mocked():
|
||||
"""Test LiteLLM with Anthropic provider using mocks."""
|
||||
def test_llm_anthropic_provider_mocked():
|
||||
"""Test LLM with Anthropic provider using mocks."""
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
messages = [{"role": "user", "content": "Hello, how are you?"}]
|
||||
@@ -117,9 +117,9 @@ def test_litellm_anthropic_provider_mocked():
|
||||
mock_response.choices = [mock_choice]
|
||||
|
||||
with patch.object(
|
||||
litellm, "completion", return_value=mock_response
|
||||
llm, "completion", return_value=mock_response
|
||||
) as mock_completion:
|
||||
response = litellm.completion(
|
||||
response = llm.completion(
|
||||
model="anthropic/claude-3-haiku-20240307",
|
||||
messages=messages,
|
||||
)
|
||||
@@ -131,10 +131,10 @@ def test_litellm_anthropic_provider_mocked():
|
||||
)
|
||||
|
||||
|
||||
# Integration tests moved to tests/e2e/test_litellm_integration.py
|
||||
# Integration tests moved to tests/e2e/test_llm_integration.py
|
||||
# They require real API keys and only run in CI
|
||||
|
||||
|
||||
# Only run this test if explicitly requested with pytest -xvs tests/test_agent/test_litellm_providers.py
|
||||
# Only run this test if explicitly requested with pytest -xvs tests/test_agent/test_llm_providers.py
|
||||
if __name__ == "__main__":
|
||||
pytest.main(["-xvs", __file__])
|
||||
@@ -55,8 +55,8 @@ async def test_agent_clarification_flow(test_project, mock_context):
|
||||
permission_manager=permission_manager, model="test-model", max_iterations=5
|
||||
)
|
||||
|
||||
# Mock the litellm completion to simulate agent requesting clarification
|
||||
with patch("litellm.completion") as mock_completion:
|
||||
# Mock the llm completion to simulate agent requesting clarification
|
||||
with patch("llm.completion") as mock_completion:
|
||||
# First call - agent reads file and asks for clarification
|
||||
mock_completion.side_effect = [
|
||||
# First iteration - read file and request clarification
|
||||
@@ -187,8 +187,8 @@ async def test_agent_critic_flow(test_project, mock_context):
|
||||
permission_manager=permission_manager, model="test-model", max_iterations=5
|
||||
)
|
||||
|
||||
# Mock the litellm completion to simulate agent requesting critic review
|
||||
with patch("litellm.completion") as mock_completion:
|
||||
# Mock the llm completion to simulate agent requesting critic review
|
||||
with patch("llm.completion") as mock_completion:
|
||||
mock_completion.side_effect = [
|
||||
# First iteration - read file
|
||||
Mock(
|
||||
@@ -307,7 +307,7 @@ async def test_clarification_limits(test_project, mock_context):
|
||||
)
|
||||
|
||||
# Test that only one clarification is allowed
|
||||
with patch("litellm.completion") as mock_completion:
|
||||
with patch("llm.completion") as mock_completion:
|
||||
mock_completion.side_effect = [
|
||||
# First clarification request
|
||||
Mock(
|
||||
@@ -388,7 +388,7 @@ async def test_critic_limits(test_project, mock_context):
|
||||
)
|
||||
|
||||
# Test that only two critic reviews are allowed
|
||||
with patch("litellm.completion") as mock_completion:
|
||||
with patch("llm.completion") as mock_completion:
|
||||
review_args = json.dumps(
|
||||
{
|
||||
"review_type": "GENERAL",
|
||||
|
||||
@@ -46,8 +46,8 @@ async def test_agent_uses_all_tools(test_project, mock_context):
|
||||
max_iterations=10, # Allow more iterations for all tools
|
||||
)
|
||||
|
||||
# Mock the litellm completion to simulate agent using all tools
|
||||
with patch("litellm.completion") as mock_completion:
|
||||
# Mock the llm completion to simulate agent using all tools
|
||||
with patch("llm.completion") as mock_completion:
|
||||
mock_completion.side_effect = [
|
||||
# 1. Read the file
|
||||
Mock(
|
||||
|
||||
+5
-5
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
"""Test that litellm deprecation warnings are properly suppressed."""
|
||||
"""Test that llm deprecation warnings are properly suppressed."""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -31,7 +31,7 @@ def test_no_pydantic_warnings():
|
||||
def test_agent_tool_no_warnings():
|
||||
"""Test that importing agent tools doesn't produce Pydantic deprecation warnings.
|
||||
|
||||
We specifically check for PydanticDeprecatedSince20 warnings from litellm,
|
||||
We specifically check for PydanticDeprecatedSince20 warnings from llm,
|
||||
not all deprecation warnings (which may come from other packages in CI).
|
||||
"""
|
||||
import warnings
|
||||
@@ -40,7 +40,7 @@ def test_agent_tool_no_warnings():
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
|
||||
# Import agent tools (which imports litellm)
|
||||
# Import agent tools (which imports llm)
|
||||
# This import happens in the test process directly
|
||||
from hanzo_tools.agent import register_tools # noqa: F401
|
||||
|
||||
@@ -53,7 +53,7 @@ def test_agent_tool_no_warnings():
|
||||
or "PydanticDeprecatedSince20" in str(warning.category.__name__)
|
||||
]
|
||||
|
||||
# We don't fail on pydantic warnings since they come from upstream litellm
|
||||
# We don't fail on pydantic warnings since they come from upstream llm
|
||||
# and we've already configured the warnings filter to suppress them
|
||||
# This test just documents that we're aware of them
|
||||
if pydantic_warnings:
|
||||
@@ -68,4 +68,4 @@ def test_agent_tool_no_warnings():
|
||||
if __name__ == "__main__":
|
||||
test_no_pydantic_warnings()
|
||||
test_agent_tool_no_warnings()
|
||||
print("✅ All litellm warning tests passed!")
|
||||
print("✅ All llm warning tests passed!")
|
||||
@@ -10,7 +10,7 @@ not at module load time.
|
||||
|
||||
Common culprits for slow imports:
|
||||
- sentence_transformers (2.5+ seconds)
|
||||
- litellm (1+ second)
|
||||
- llm (1+ second)
|
||||
- hanzo_memory embedding services (3+ seconds)
|
||||
"""
|
||||
|
||||
@@ -63,7 +63,7 @@ print(f"ELAPSED:{elapsed:.3f}")
|
||||
assert elapsed < MAX_MODULE_IMPORT_TIME, (
|
||||
f"hanzo_mcp.tools import took {elapsed:.2f}s (max: {MAX_MODULE_IMPORT_TIME}s). "
|
||||
"This is too slow! Check for heavy imports at module load time. "
|
||||
"Common culprits: sentence_transformers, litellm, hanzo_memory"
|
||||
"Common culprits: sentence_transformers, llm, hanzo_memory"
|
||||
)
|
||||
|
||||
def test_no_heavy_imports_at_module_level(self):
|
||||
@@ -72,7 +72,7 @@ print(f"ELAPSED:{elapsed:.3f}")
|
||||
import sys
|
||||
# Clear any cached modules
|
||||
for mod in list(sys.modules.keys()):
|
||||
if any(x in mod for x in ['hanzo', 'sentence', 'litellm']):
|
||||
if any(x in mod for x in ['hanzo', 'sentence', 'llm']):
|
||||
del sys.modules[mod]
|
||||
|
||||
# Import the tools module
|
||||
@@ -80,7 +80,7 @@ import hanzo_mcp.tools
|
||||
|
||||
# Check what got imported
|
||||
heavy_modules = []
|
||||
for name in ['sentence_transformers', 'litellm', 'hanzo_memory']:
|
||||
for name in ['sentence_transformers', 'llm', 'hanzo_memory']:
|
||||
if name in sys.modules:
|
||||
heavy_modules.append(name)
|
||||
|
||||
|
||||
@@ -226,8 +226,8 @@ class MockServiceHelper:
|
||||
return mock_service
|
||||
|
||||
@staticmethod
|
||||
def mock_litellm_completion(response: str = "Test response"):
|
||||
"""Create a mock litellm completion."""
|
||||
def mock_llm_completion(response: str = "Test response"):
|
||||
"""Create a mock llm completion."""
|
||||
mock_response = Mock()
|
||||
mock_response.choices = [Mock(message=Mock(content=response))]
|
||||
return Mock(return_value=mock_response)
|
||||
|
||||
@@ -7,7 +7,7 @@ existing tools without requiring networked services:
|
||||
- Linear MCP server registration via mcp_add + visibility in mcp_stats
|
||||
- Per-task git worktree creation via bash
|
||||
|
||||
Network calls are not performed. LLM calls are mocked via litellm patching.
|
||||
Network calls are not performed. LLM calls are mocked via llm patching.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -41,7 +41,7 @@ from test_utils import PermissionManager
|
||||
|
||||
|
||||
def _mock_acompletion_factory(responses: Dict[str, str]):
|
||||
"""Create a litellm.acompletion mock that returns responses by keyword.
|
||||
"""Create a llm.acompletion mock that returns responses by keyword.
|
||||
|
||||
The first matching keyword in the prompt determines the returned text.
|
||||
Defaults to a simple echo if nothing matches.
|
||||
@@ -77,7 +77,7 @@ def _mock_acompletion_factory(responses: Dict[str, str]):
|
||||
async def test_architecture_and_task_gen_with_consensus_mock(
|
||||
monkeypatch, tmp_path: Path
|
||||
):
|
||||
"""Architecture → tasks flow using LLMTool with litellm mocked.
|
||||
"""Architecture → tasks flow using LLMTool with llm mocked.
|
||||
|
||||
- Generates an architecture.md file
|
||||
- Generates JSON tasks from the architecture
|
||||
|
||||
@@ -42,9 +42,9 @@ class Settings(BaseSettings):
|
||||
Path("data/lancedb"), description="Path to LanceDB data directory"
|
||||
)
|
||||
|
||||
# LLM Settings (LiteLLM compatible)
|
||||
# LLM Settings (LLM compatible)
|
||||
llm_model: str = Field(
|
||||
"gpt-4o-mini", description="LLM model to use (LiteLLM format)"
|
||||
"gpt-4o-mini", description="LLM model to use (LLM format)"
|
||||
)
|
||||
llm_api_base: str | None = Field(None, description="API base URL for local models")
|
||||
llm_api_key: str | None = Field(None, description="API key for LLM provider")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""LLM service for AI operations using LiteLLM."""
|
||||
"""LLM service for AI operations using LLM."""
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
@@ -9,22 +9,22 @@ from ..config import settings
|
||||
|
||||
logger = get_logger()
|
||||
|
||||
# Try to import LiteLLM, but make it optional
|
||||
# Try to import LLM, but make it optional
|
||||
try:
|
||||
import litellm
|
||||
import llm
|
||||
|
||||
LITELLM_AVAILABLE = True
|
||||
# Configure LiteLLM
|
||||
litellm.drop_params = True # Drop unsupported params instead of failing
|
||||
litellm.set_verbose = False # Disable verbose logging
|
||||
LLM_AVAILABLE = True
|
||||
# Configure LLM
|
||||
llm.drop_params = True # Drop unsupported params instead of failing
|
||||
llm.set_verbose = False # Disable verbose logging
|
||||
except ImportError:
|
||||
LITELLM_AVAILABLE = False
|
||||
litellm = None
|
||||
logger.warning("LiteLLM not available, LLM features will be limited")
|
||||
LLM_AVAILABLE = False
|
||||
llm = None
|
||||
logger.warning("LLM not available, LLM features will be limited")
|
||||
|
||||
|
||||
class LLMService:
|
||||
"""Service for LLM operations using LiteLLM."""
|
||||
"""Service for LLM operations using LLM."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize LLM service."""
|
||||
@@ -33,15 +33,15 @@ class LLMService:
|
||||
self.temperature = settings.llm_temperature
|
||||
self.max_tokens = settings.llm_max_tokens
|
||||
|
||||
# Set up API keys if LiteLLM is available
|
||||
if LITELLM_AVAILABLE:
|
||||
# Set up API keys if LLM is available
|
||||
if LLM_AVAILABLE:
|
||||
# Set up API keys
|
||||
if settings.llm_api_key:
|
||||
litellm.api_key = settings.llm_api_key
|
||||
llm.api_key = settings.llm_api_key
|
||||
if settings.openai_api_key:
|
||||
litellm.openai_key = settings.openai_api_key
|
||||
llm.openai_key = settings.openai_api_key
|
||||
if settings.anthropic_api_key:
|
||||
litellm.anthropic_key = settings.anthropic_api_key
|
||||
llm.anthropic_key = settings.anthropic_api_key
|
||||
|
||||
def complete(
|
||||
self,
|
||||
@@ -52,7 +52,7 @@ class LLMService:
|
||||
response_format: str | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Complete a prompt using LiteLLM.
|
||||
Complete a prompt using LLM.
|
||||
|
||||
Args:
|
||||
prompt: The prompt to complete
|
||||
@@ -64,8 +64,8 @@ class LLMService:
|
||||
Returns:
|
||||
Generated text
|
||||
"""
|
||||
if not LITELLM_AVAILABLE:
|
||||
logger.warning("LiteLLM not available, returning empty response")
|
||||
if not LLM_AVAILABLE:
|
||||
logger.warning("LLM not available, returning empty response")
|
||||
return ""
|
||||
|
||||
model = model or self.default_model
|
||||
@@ -88,7 +88,7 @@ class LLMService:
|
||||
if response_format == "json":
|
||||
kwargs["response_format"] = {"type": "json_object"}
|
||||
|
||||
response = litellm.completion(**kwargs)
|
||||
response = llm.completion(**kwargs)
|
||||
return response.choices[0].message.content or ""
|
||||
except Exception as e:
|
||||
logger.error(f"LLM completion error: {e}")
|
||||
@@ -103,7 +103,7 @@ class LLMService:
|
||||
response_format: str | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Chat with the LLM using LiteLLM.
|
||||
Chat with the LLM using LLM.
|
||||
|
||||
Args:
|
||||
messages: List of message dicts with "role" and "content"
|
||||
@@ -115,8 +115,8 @@ class LLMService:
|
||||
Returns:
|
||||
Generated response
|
||||
"""
|
||||
if not LITELLM_AVAILABLE:
|
||||
logger.warning("LiteLLM not available, returning empty response")
|
||||
if not LLM_AVAILABLE:
|
||||
logger.warning("LLM not available, returning empty response")
|
||||
return ""
|
||||
|
||||
model = model or self.default_model
|
||||
@@ -139,7 +139,7 @@ class LLMService:
|
||||
if response_format == "json":
|
||||
kwargs["response_format"] = {"type": "json_object"}
|
||||
|
||||
response = litellm.completion(**kwargs)
|
||||
response = llm.completion(**kwargs)
|
||||
return response.choices[0].message.content or ""
|
||||
except Exception as e:
|
||||
logger.error(f"LLM chat error: {e}")
|
||||
@@ -188,7 +188,7 @@ Content: {content}"""
|
||||
summary = self.complete(summary_prompt, temperature=0.3)
|
||||
|
||||
# Generate knowledge instructions
|
||||
if LITELLM_AVAILABLE:
|
||||
if LLM_AVAILABLE:
|
||||
instruction_prompt = f"""Based on this summary, generate instructions for updating a knowledge base.
|
||||
Return a JSON object with the following structure:
|
||||
{{
|
||||
|
||||
@@ -57,9 +57,9 @@ def mock_embedding_model():
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_litellm_completion():
|
||||
"""Mock LiteLLM completion to avoid API calls during tests."""
|
||||
with patch("litellm.completion") as mock_completion:
|
||||
def mock_llm_completion():
|
||||
"""Mock LLM completion to avoid API calls during tests."""
|
||||
with patch("llm.completion") as mock_completion:
|
||||
# Create mock response
|
||||
mock_response = MagicMock()
|
||||
mock_response.choices = [
|
||||
|
||||
@@ -139,7 +139,7 @@ class TestAdditionalCoverage:
|
||||
from hanzo_memory.services.llm import LLMService
|
||||
|
||||
with patch("hanzo_memory.services.llm.settings") as mock_settings:
|
||||
with patch("hanzo_memory.services.llm.litellm") as mock_litellm:
|
||||
with patch("hanzo_memory.services.llm.llm") as mock_llm:
|
||||
# Test with llm_api_key
|
||||
mock_settings.llm_model = "test"
|
||||
mock_settings.llm_api_base = None
|
||||
@@ -150,21 +150,21 @@ class TestAdditionalCoverage:
|
||||
mock_settings.anthropic_api_key = None
|
||||
|
||||
LLMService()
|
||||
assert mock_litellm.api_key == "test-llm-key"
|
||||
assert mock_llm.api_key == "test-llm-key"
|
||||
|
||||
# Test with openai_api_key
|
||||
mock_settings.llm_api_key = None
|
||||
mock_settings.openai_api_key = "test-openai-key"
|
||||
|
||||
LLMService()
|
||||
assert mock_litellm.openai_key == "test-openai-key"
|
||||
assert mock_llm.openai_key == "test-openai-key"
|
||||
|
||||
# Test with anthropic_api_key
|
||||
mock_settings.openai_api_key = None
|
||||
mock_settings.anthropic_api_key = "test-anthropic-key"
|
||||
|
||||
LLMService()
|
||||
assert mock_litellm.anthropic_key == "test-anthropic-key"
|
||||
assert mock_llm.anthropic_key == "test-anthropic-key"
|
||||
|
||||
def test_embedding_service_empty_list(self):
|
||||
"""Test embedding service with empty list."""
|
||||
|
||||
@@ -11,7 +11,7 @@ class TestLLMService:
|
||||
"""Test LLM service."""
|
||||
|
||||
@pytest.fixture
|
||||
def llm_service(self, mock_litellm_completion):
|
||||
def llm_service(self, mock_llm_completion):
|
||||
"""Create LLM service."""
|
||||
|
||||
# Configure mock to return appropriate responses
|
||||
@@ -36,7 +36,7 @@ class TestLLMService:
|
||||
mock_response.choices = [mock_choice]
|
||||
return mock_response
|
||||
|
||||
mock_litellm_completion.side_effect = side_effect
|
||||
mock_llm_completion.side_effect = side_effect
|
||||
return LLMService()
|
||||
|
||||
def test_complete(self, llm_service):
|
||||
|
||||
@@ -319,7 +319,7 @@ class HanzoDevBackend(Backend):
|
||||
|
||||
|
||||
class EmbeddedBackend(Backend):
|
||||
"""Embedded LLM backend using litellm."""
|
||||
"""Embedded LLM backend using llm."""
|
||||
|
||||
def __init__(self, llm_client):
|
||||
self.llm_client = llm_client
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import os
|
||||
from typing import Any, Dict, List, Optional, Set
|
||||
|
||||
from litellm import acompletion, completion
|
||||
from llm import acompletion, completion
|
||||
|
||||
|
||||
class LLMClient:
|
||||
|
||||
@@ -10,7 +10,7 @@ import time
|
||||
import uuid
|
||||
import asyncio
|
||||
|
||||
# Import litellm with warnings suppressed
|
||||
# Import llm with warnings suppressed
|
||||
import warnings
|
||||
from typing import (
|
||||
Any,
|
||||
|
||||
@@ -114,7 +114,7 @@ def get_default_model(model_override: str | None = None) -> str:
|
||||
"""Get the default model for agent execution.
|
||||
|
||||
Args:
|
||||
model_override: Optional model override string in LiteLLM format (e.g., "openai/gpt-4o")
|
||||
model_override: Optional model override string in LLM format (e.g., "openai/gpt-4o")
|
||||
|
||||
Returns:
|
||||
Model identifier string with provider prefix
|
||||
|
||||
@@ -5,7 +5,7 @@ formats, making MCP tools available to the OpenAI API, and processing tool input
|
||||
and outputs for agent execution.
|
||||
"""
|
||||
|
||||
# Import litellm with warnings suppressed
|
||||
# Import llm with warnings suppressed
|
||||
import warnings
|
||||
|
||||
from openai.types import FunctionParameters
|
||||
@@ -71,12 +71,12 @@ 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")
|
||||
model: Model identifier in LLM 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
|
||||
# Since llm 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
|
||||
|
||||
@@ -178,10 +178,10 @@ class TestToolPackages:
|
||||
reason="hanzo-tools-llm not installed",
|
||||
)
|
||||
def test_llm_tools(self):
|
||||
"""Test hanzo-tools-llm imports (tools depend on litellm)."""
|
||||
"""Test hanzo-tools-llm imports (tools depend on llm)."""
|
||||
from hanzo_tools.llm import TOOLS, LLM_AVAILABLE
|
||||
|
||||
# LLM tools are optional, depend on litellm
|
||||
# LLM tools are optional, depend on llm
|
||||
if LLM_AVAILABLE:
|
||||
assert len(TOOLS) >= 1
|
||||
else:
|
||||
@@ -214,7 +214,7 @@ REQUIRED_IMPORT_MODULES = [
|
||||
("hanzo_tools.refactor", 1.0),
|
||||
("hanzo_tools.jupyter", 1.0),
|
||||
("hanzo_tools.browser", 1.0),
|
||||
("hanzo_tools.agent", 2.0), # Agent has litellm, allow more time
|
||||
("hanzo_tools.agent", 2.0), # Agent has llm, allow more time
|
||||
]
|
||||
|
||||
# Optional packages that may not be installed
|
||||
@@ -223,7 +223,7 @@ OPTIONAL_IMPORT_MODULES = [
|
||||
("hanzo_tools.mcp_tools", 1.0),
|
||||
("hanzo_tools.database", 1.0),
|
||||
("hanzo_tools.editor", 1.0),
|
||||
("hanzo_tools.llm", 2.0), # LLM has litellm, allow more time
|
||||
("hanzo_tools.llm", 2.0), # LLM has llm, allow more time
|
||||
("hanzo_tools.vector", 2.0), # Vector has heavy deps
|
||||
]
|
||||
|
||||
|
||||
@@ -275,14 +275,14 @@ Providers are automatically detected based on environment variables:
|
||||
return f"{provider} is already disabled"
|
||||
|
||||
def _list_all_models(self, provider: Optional[str] = None) -> str:
|
||||
"""List all available models from LiteLLM."""
|
||||
"""List all available models from LLM."""
|
||||
try:
|
||||
from .llm_unified import LLMTool
|
||||
|
||||
all_models = LLMTool.get_all_models()
|
||||
|
||||
if not all_models:
|
||||
return "No models available or LiteLLM not installed"
|
||||
return "No models available or LLM not installed"
|
||||
|
||||
output = ["=== Available LLM Models ==="]
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@ from mcp.server.fastmcp import Context as MCPContext
|
||||
|
||||
from hanzo_tools.core import BaseTool, ToolContext, auto_timeout, create_tool_context
|
||||
|
||||
# Check if litellm is available
|
||||
# Check if llm is available
|
||||
try:
|
||||
import litellm
|
||||
import llm
|
||||
|
||||
LITELLM_AVAILABLE = True
|
||||
LLM_AVAILABLE = True
|
||||
except ImportError:
|
||||
LITELLM_AVAILABLE = False
|
||||
LLM_AVAILABLE = False
|
||||
|
||||
|
||||
# Parameter types
|
||||
@@ -280,9 +280,9 @@ Available: {", ".join(available) if available else "None"}"""
|
||||
# Running in test mode without MCP context
|
||||
pass
|
||||
|
||||
if not LITELLM_AVAILABLE:
|
||||
if not LLM_AVAILABLE:
|
||||
return (
|
||||
"Error: LiteLLM is not installed. Install it with: pip install litellm"
|
||||
"Error: LLM is not installed. Install it with: pip install llm"
|
||||
)
|
||||
|
||||
# Extract action
|
||||
@@ -368,13 +368,13 @@ Available: {", ".join(available) if available else "None"}"""
|
||||
if kwargs.get("stream"):
|
||||
# Handle streaming response
|
||||
response_text = ""
|
||||
async for chunk in await litellm.acompletion(**kwargs):
|
||||
async for chunk in await llm.acompletion(**kwargs):
|
||||
if chunk.choices[0].delta.content:
|
||||
response_text += chunk.choices[0].delta.content
|
||||
return response_text
|
||||
else:
|
||||
# Regular response
|
||||
response = await litellm.acompletion(**kwargs)
|
||||
response = await llm.acompletion(**kwargs)
|
||||
return response.choices[0].message.content
|
||||
|
||||
except Exception as e:
|
||||
@@ -517,7 +517,7 @@ Provide your critical analysis:"""
|
||||
all_models = self._get_all_models()
|
||||
|
||||
if not all_models:
|
||||
return "No models available or LiteLLM not properly initialized"
|
||||
return "No models available or LLM not properly initialized"
|
||||
|
||||
output = ["=== Available LLM Models ==="]
|
||||
|
||||
@@ -623,7 +623,7 @@ Provide your critical analysis:"""
|
||||
if tool_ctx:
|
||||
await tool_ctx.info(f"Testing {model}...")
|
||||
|
||||
response = await litellm.acompletion(
|
||||
response = await llm.acompletion(
|
||||
model=model,
|
||||
messages=[{"role": "user", "content": test_prompt}],
|
||||
temperature=0,
|
||||
@@ -739,7 +739,7 @@ Provide your critical analysis:"""
|
||||
if max_tokens:
|
||||
kwargs["max_tokens"] = max_tokens
|
||||
|
||||
response = await litellm.acompletion(**kwargs)
|
||||
response = await llm.acompletion(**kwargs)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
@@ -869,12 +869,12 @@ Be concise and highlight the most important findings."""
|
||||
return "openai"
|
||||
|
||||
def _get_all_models(self) -> Dict[str, List[str]]:
|
||||
"""Get all available models from LiteLLM."""
|
||||
"""Get all available models from LLM."""
|
||||
try:
|
||||
import litellm
|
||||
import llm
|
||||
|
||||
# Get all models
|
||||
all_models = litellm.model_list
|
||||
all_models = llm.model_list
|
||||
|
||||
# Organize by provider
|
||||
providers = {}
|
||||
|
||||
@@ -135,8 +135,8 @@ async def ask_once(
|
||||
try:
|
||||
from pkg.hanzoai import completion
|
||||
except ImportError:
|
||||
# Fallback to using litellm directly
|
||||
import litellm
|
||||
# Fallback to using llm directly
|
||||
import llm
|
||||
|
||||
def completion(**kwargs):
|
||||
import os
|
||||
@@ -145,7 +145,7 @@ async def ask_once(
|
||||
if api_key:
|
||||
kwargs["api_key"] = api_key
|
||||
kwargs["api_base"] = "https://api.hanzo.ai/v1"
|
||||
return litellm.completion(**kwargs)
|
||||
return llm.completion(**kwargs)
|
||||
|
||||
result = completion(
|
||||
model=f"anthropic/{model}" if "claude" in model else model,
|
||||
@@ -154,7 +154,7 @@ async def ask_once(
|
||||
content = result.choices[0].message.content
|
||||
except ImportError as e:
|
||||
console.print(f"[red]Error:[/red] Missing dependencies: {e}")
|
||||
console.print("Install with: pip install litellm")
|
||||
console.print("Install with: pip install llm")
|
||||
return
|
||||
|
||||
# Display response
|
||||
@@ -219,8 +219,8 @@ async def interactive_chat(ctx, model: str, local: bool, system: Optional[str]):
|
||||
try:
|
||||
from pkg.hanzoai import completion
|
||||
except ImportError:
|
||||
# Fallback to using litellm directly
|
||||
import litellm
|
||||
# Fallback to using llm directly
|
||||
import llm
|
||||
|
||||
def completion(**kwargs):
|
||||
import os
|
||||
@@ -229,7 +229,7 @@ async def interactive_chat(ctx, model: str, local: bool, system: Optional[str]):
|
||||
if api_key:
|
||||
kwargs["api_key"] = api_key
|
||||
kwargs["api_base"] = "https://api.hanzo.ai/v1"
|
||||
return litellm.completion(**kwargs)
|
||||
return llm.completion(**kwargs)
|
||||
|
||||
result = completion(
|
||||
model=f"anthropic/{model}" if "claude" in model else model,
|
||||
|
||||
@@ -107,7 +107,7 @@ TOOLS = {
|
||||
# Go tools (go install)
|
||||
"router": {
|
||||
"name": "Hanzo Router",
|
||||
"description": "LLM Gateway/Router (LiteLLM proxy)",
|
||||
"description": "LLM Gateway/Router (LLM proxy)",
|
||||
"source": "docker",
|
||||
"image": "ghcr.io/hanzoai/llm:latest",
|
||||
"binary": None,
|
||||
|
||||
@@ -33,7 +33,7 @@ def start_router(ctx, port: int, config: Optional[str], detach: bool):
|
||||
|
||||
router_dir = None
|
||||
for path in router_paths:
|
||||
if path.exists() and (path / "litellm" / "proxy" / "proxy_server.py").exists():
|
||||
if path.exists() and (path / "llm" / "proxy" / "proxy_server.py").exists():
|
||||
router_dir = path
|
||||
break
|
||||
|
||||
@@ -55,7 +55,7 @@ def start_router(ctx, port: int, config: Optional[str], detach: bool):
|
||||
cmd = [
|
||||
sys.executable,
|
||||
"-m",
|
||||
"litellm.proxy.proxy_server",
|
||||
"llm.proxy.proxy_server",
|
||||
"--port",
|
||||
str(port),
|
||||
]
|
||||
|
||||
+23
-23
@@ -8,14 +8,14 @@ complementing the full-featured auto-generated client.
|
||||
import os
|
||||
from typing import Optional
|
||||
|
||||
# We can import and use litellm as a dependency
|
||||
# We can import and use llm as a dependency
|
||||
try:
|
||||
import litellm
|
||||
import llm
|
||||
|
||||
LITELLM_AVAILABLE = True
|
||||
LLM_AVAILABLE = True
|
||||
except ImportError:
|
||||
LITELLM_AVAILABLE = False
|
||||
litellm = None
|
||||
LLM_AVAILABLE = False
|
||||
llm = None
|
||||
|
||||
from ._client import Hanzo
|
||||
|
||||
@@ -29,7 +29,7 @@ HANZO_API_KEY = os.getenv("HANZO_API_KEY")
|
||||
|
||||
class SimpleLLMClient:
|
||||
"""
|
||||
Simple LLM client for Hanzo AI with litellm compatibility.
|
||||
Simple LLM client for Hanzo AI with llm compatibility.
|
||||
|
||||
This provides a simpler interface that's compatible with the
|
||||
patterns from the llm/hanzoai package, while using the
|
||||
@@ -72,12 +72,12 @@ class SimpleLLMClient:
|
||||
# Create the underlying Hanzo client
|
||||
self._client = Hanzo(api_key=self.api_key, base_url=self.api_base)
|
||||
|
||||
# Configure litellm if available
|
||||
if LITELLM_AVAILABLE and litellm:
|
||||
litellm.api_base = self.api_base
|
||||
litellm.drop_params = True # Be permissive with params
|
||||
# Configure llm if available
|
||||
if LLM_AVAILABLE and llm:
|
||||
llm.api_base = self.api_base
|
||||
llm.drop_params = True # Be permissive with params
|
||||
if self.api_key:
|
||||
litellm.api_key = self.api_key
|
||||
llm.api_key = self.api_key
|
||||
os.environ["OPENAI_API_KEY"] = self.api_key # For OpenAI compatibility
|
||||
|
||||
def _iam_login(self):
|
||||
@@ -129,38 +129,38 @@ class SimpleLLMClient:
|
||||
"""
|
||||
Create a completion using Hanzo AI.
|
||||
|
||||
If litellm is available, uses litellm for compatibility.
|
||||
If llm is available, uses llm for compatibility.
|
||||
Otherwise uses the native client.
|
||||
"""
|
||||
if LITELLM_AVAILABLE and litellm:
|
||||
# Use litellm for maximum compatibility
|
||||
if LLM_AVAILABLE and llm:
|
||||
# Use llm for maximum compatibility
|
||||
kwargs.setdefault("api_base", self.api_base)
|
||||
if self.iam_token:
|
||||
kwargs.setdefault("api_key", f"Bearer iam_{self.iam_token}")
|
||||
elif self.api_key:
|
||||
kwargs.setdefault("api_key", self.api_key)
|
||||
return litellm.completion(**kwargs)
|
||||
return llm.completion(**kwargs)
|
||||
else:
|
||||
# Use native client
|
||||
return self._client.chat.completions.create(**kwargs)
|
||||
|
||||
def embedding(self, **kwargs):
|
||||
"""Create embeddings using Hanzo AI."""
|
||||
if LITELLM_AVAILABLE and litellm:
|
||||
if LLM_AVAILABLE and llm:
|
||||
kwargs.setdefault("api_base", self.api_base)
|
||||
if self.api_key:
|
||||
kwargs.setdefault("api_key", self.api_key)
|
||||
return litellm.embedding(**kwargs)
|
||||
return llm.embedding(**kwargs)
|
||||
else:
|
||||
return self._client.embeddings.create(**kwargs)
|
||||
|
||||
def image_generation(self, **kwargs):
|
||||
"""Generate images using Hanzo AI."""
|
||||
if LITELLM_AVAILABLE and litellm:
|
||||
if LLM_AVAILABLE and llm:
|
||||
kwargs.setdefault("api_base", self.api_base)
|
||||
if self.api_key:
|
||||
kwargs.setdefault("api_key", self.api_key)
|
||||
return litellm.image_generation(**kwargs)
|
||||
return llm.image_generation(**kwargs)
|
||||
else:
|
||||
return self._client.images.generations.create(**kwargs)
|
||||
|
||||
@@ -218,8 +218,8 @@ def completion(**kwargs):
|
||||
if HANZO_API_KEY:
|
||||
kwargs.setdefault("api_key", HANZO_API_KEY)
|
||||
|
||||
if LITELLM_AVAILABLE and litellm:
|
||||
return litellm.completion(**kwargs)
|
||||
if LLM_AVAILABLE and llm:
|
||||
return llm.completion(**kwargs)
|
||||
else:
|
||||
client = SimpleLLMClient()
|
||||
return client.completion(**kwargs)
|
||||
@@ -230,8 +230,8 @@ def set_api_key(api_key: str):
|
||||
global HANZO_API_KEY
|
||||
HANZO_API_KEY = api_key
|
||||
os.environ["HANZO_API_KEY"] = api_key
|
||||
if LITELLM_AVAILABLE and litellm:
|
||||
litellm.api_key = api_key
|
||||
if LLM_AVAILABLE and llm:
|
||||
llm.api_key = api_key
|
||||
os.environ["OPENAI_API_KEY"] = api_key
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ classifiers = [
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
litellm = ["hanzo-llm>=1.0.0"]
|
||||
llm = ["hanzo-llm>=1.0.0"]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/hanzoai/python-sdk"
|
||||
|
||||
@@ -150,7 +150,7 @@ Modular tool package system with entry-point based discovery:
|
||||
### Phase 3: Migration from existing memory system
|
||||
- [ ] Import important memories from hanzo-memory package
|
||||
- [ ] Provide migration tools for existing vector data
|
||||
- [ ] Deprecate complex LiteLLM/InfinityDB system
|
||||
- [ ] Deprecate complex LLM/InfinityDB system
|
||||
|
||||
### Phase 4: Full optimization
|
||||
- [ ] Keep SQLite for structured data (file metadata, symbols, graph)
|
||||
|
||||
Reference in New Issue
Block a user