DETERMINATOR / src /utils /llm_factory.py
Joseph Pollack
attempts to solve the websearch , adds serper , adds tools , adds adapter , solves settings issue , adds some more stuff basically
30d71e1 unverified
"""Centralized LLM client factory.
This module provides factory functions for creating LLM clients,
ensuring consistent configuration and clear error messages.
Agent-Framework Chat Clients:
- HuggingFace InferenceClient: Native function calling support via 'tools' parameter
- OpenAI ChatClient: Native function calling support (original implementation)
- Both can be used with agent-framework's ChatAgent
Pydantic AI Models:
- Default provider is HuggingFace (free tier, no API key required for public models)
- OpenAI and Anthropic are available as fallback options
- All providers use Pydantic AI's unified interface
"""
from typing import TYPE_CHECKING, Any
from src.utils.config import settings
from src.utils.exceptions import ConfigurationError
if TYPE_CHECKING:
from agent_framework.openai import OpenAIChatClient
from src.utils.huggingface_chat_client import HuggingFaceChatClient
def get_magentic_client() -> "OpenAIChatClient":
"""
Get the OpenAI client for Magentic agents (legacy function).
Note: This function is kept for backward compatibility.
For new code, use get_chat_client_for_agent() which supports
both OpenAI and HuggingFace.
Raises:
ConfigurationError: If OPENAI_API_KEY is not set
Returns:
Configured OpenAIChatClient for Magentic agents
"""
# Import here to avoid requiring agent-framework for simple mode
from agent_framework.openai import OpenAIChatClient
api_key = settings.get_openai_api_key()
return OpenAIChatClient(
model_id=settings.openai_model,
api_key=api_key,
)
def get_huggingface_chat_client(oauth_token: str | None = None) -> "HuggingFaceChatClient":
"""
Get HuggingFace chat client for agent-framework.
HuggingFace InferenceClient natively supports function calling,
making it compatible with agent-framework's ChatAgent.
Args:
oauth_token: Optional OAuth token from HuggingFace login (takes priority over env vars)
Returns:
Configured HuggingFaceChatClient
Raises:
ConfigurationError: If initialization fails
"""
from src.utils.huggingface_chat_client import HuggingFaceChatClient
model_name = settings.huggingface_model or "meta-llama/Llama-3.1-8B-Instruct"
# Priority: oauth_token > env vars
api_key = oauth_token or settings.hf_token or settings.huggingface_api_key
return HuggingFaceChatClient(
model_name=model_name,
api_key=api_key,
provider="auto", # Auto-select best provider
)
def get_chat_client_for_agent(oauth_token: str | None = None) -> Any:
"""
Get appropriate chat client for agent-framework based on configuration.
Supports:
- HuggingFace InferenceClient (if HF_TOKEN available, preferred for free tier)
- OpenAI ChatClient (if OPENAI_API_KEY available, fallback)
Args:
oauth_token: Optional OAuth token from HuggingFace login (takes priority over env vars)
Returns:
ChatClient compatible with agent-framework (HuggingFaceChatClient or OpenAIChatClient)
Raises:
ConfigurationError: If no suitable client can be created
"""
# Check if we have OAuth token or env vars
has_hf_key = bool(oauth_token or settings.has_huggingface_key)
# Prefer HuggingFace if available (free tier)
if has_hf_key:
return get_huggingface_chat_client(oauth_token=oauth_token)
# Fallback to OpenAI if available
if settings.has_openai_key:
return get_magentic_client()
# If neither available, try HuggingFace without key (public models)
try:
return get_huggingface_chat_client(oauth_token=oauth_token)
except Exception:
pass
raise ConfigurationError(
"No chat client available. Set HF_TOKEN or OPENAI_API_KEY for agent-framework mode."
)
def get_pydantic_ai_model(oauth_token: str | None = None) -> Any:
"""
Get the appropriate model for pydantic-ai based on configuration.
Uses the configured LLM_PROVIDER to select between HuggingFace, OpenAI, and Anthropic.
Defaults to HuggingFace if provider is not specified or unknown.
This is used by simple mode components (JudgeHandler, etc.)
Args:
oauth_token: Optional OAuth token from HuggingFace login (takes priority over env vars)
Returns:
Configured pydantic-ai model
"""
from pydantic_ai.models.huggingface import HuggingFaceModel
from pydantic_ai.providers.huggingface import HuggingFaceProvider
# Priority: oauth_token > settings.hf_token > settings.huggingface_api_key
effective_hf_token = oauth_token or settings.hf_token or settings.huggingface_api_key
# HuggingFaceProvider requires a token - cannot use None
if not effective_hf_token:
raise ConfigurationError(
"HuggingFace token required. Please either:\n"
"1. Log in via HuggingFace OAuth (recommended for Spaces)\n"
"2. Set HF_TOKEN environment variable\n"
"3. Set huggingface_api_key in settings"
)
# Always use HuggingFace with available token
model_name = settings.huggingface_model or "meta-llama/Llama-3.1-8B-Instruct"
hf_provider = HuggingFaceProvider(api_key=effective_hf_token)
return HuggingFaceModel(model_name, provider=hf_provider)
def check_magentic_requirements() -> None:
"""
Check if Magentic/agent-framework mode requirements are met.
Note: HuggingFace InferenceClient now supports function calling natively,
so this check is relaxed. We prefer HuggingFace if available, fallback to OpenAI.
Raises:
ConfigurationError: If no suitable client can be created
"""
# Try to get a chat client - will raise if none available
try:
get_chat_client_for_agent()
except ConfigurationError as e:
raise ConfigurationError(
"Agent-framework mode requires HF_TOKEN or OPENAI_API_KEY. "
"HuggingFace is preferred (free tier with function calling support). "
"Use mode='simple' for other LLM providers."
) from e
def check_simple_mode_requirements() -> None:
"""
Check if simple mode requirements are met.
Simple mode supports HuggingFace (default), OpenAI, and Anthropic.
HuggingFace can work without an API key for public models.
Raises:
ConfigurationError: If no LLM is available (only if explicitly required)
"""
# HuggingFace can work without API key for public models, so we don't require it
# This allows simple mode to work out of the box
pass