From b3f371ba51c1c6e4a3ad06aabefc84dc96558705 Mon Sep 17 00:00:00 2001 From: ShellyBot Date: Thu, 14 May 2026 14:17:05 -0400 Subject: [PATCH] fix(llm): pass base_url to default provider clients from LLMSettings (#643) * fix(llm): pass base_url to default provider clients from LLMSettings Fixes plastic-labs/honcho#641 * fix(registry): use public genai.Client instead of genai.client.Client --------- Co-authored-by: Hermes Agent Co-authored-by: ShellyBot --- src/config.py | 6 ++++++ src/llm/registry.py | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/config.py b/src/config.py index a4e814f8..5c161eda 100644 --- a/src/config.py +++ b/src/config.py @@ -648,6 +648,12 @@ class LLMSettings(HonchoSettings): OPENAI_API_KEY: str | None = None GEMINI_API_KEY: str | None = None + # Base URLs for LLM providers (for OpenAI-compatible proxies like + # OpenRouter, vLLM, Together, Anyscale, self-hosted, etc.) + ANTHROPIC_BASE_URL: str | None = None + OPENAI_BASE_URL: str | None = None + GEMINI_BASE_URL: str | None = None + # General LLM settings DEFAULT_MAX_TOKENS: Annotated[int, Field(default=1000, gt=0, le=100_000)] = 2500 diff --git a/src/llm/registry.py b/src/llm/registry.py index 73cf60c8..d89f088d 100644 --- a/src/llm/registry.py +++ b/src/llm/registry.py @@ -38,6 +38,7 @@ def get_anthropic_client() -> AsyncAnthropic: """Default Anthropic client built from settings.LLM.ANTHROPIC_API_KEY.""" return AsyncAnthropic( api_key=settings.LLM.ANTHROPIC_API_KEY, + base_url=settings.LLM.ANTHROPIC_BASE_URL, timeout=600.0, ) @@ -47,13 +48,19 @@ def get_openai_client() -> AsyncOpenAI: """Default OpenAI client built from settings.LLM.OPENAI_API_KEY.""" return AsyncOpenAI( api_key=settings.LLM.OPENAI_API_KEY, + base_url=settings.LLM.OPENAI_BASE_URL, ) @lru_cache(maxsize=1) def get_gemini_client() -> genai.Client: """Default Gemini client built from settings.LLM.GEMINI_API_KEY.""" - return genai.Client(api_key=settings.LLM.GEMINI_API_KEY) + http_options = ( + genai_types.HttpOptions(base_url=settings.LLM.GEMINI_BASE_URL) + if settings.LLM.GEMINI_BASE_URL + else None + ) + return genai.Client(api_key=settings.LLM.GEMINI_API_KEY, http_options=http_options) # Bounded cache — in practice the (base_url, api_key) key space is small @@ -91,17 +98,25 @@ CLIENTS: dict[ModelTransport, ProviderClient] = {} if settings.LLM.ANTHROPIC_API_KEY: CLIENTS["anthropic"] = AsyncAnthropic( api_key=settings.LLM.ANTHROPIC_API_KEY, + base_url=settings.LLM.ANTHROPIC_BASE_URL, timeout=600.0, ) if settings.LLM.OPENAI_API_KEY: CLIENTS["openai"] = AsyncOpenAI( api_key=settings.LLM.OPENAI_API_KEY, + base_url=settings.LLM.OPENAI_BASE_URL, ) if settings.LLM.GEMINI_API_KEY: - CLIENTS["gemini"] = genai.client.Client( + http_options = ( + genai_types.HttpOptions(base_url=settings.LLM.GEMINI_BASE_URL) + if settings.LLM.GEMINI_BASE_URL + else None + ) + CLIENTS["gemini"] = genai.Client( api_key=settings.LLM.GEMINI_API_KEY, + http_options=http_options, )