Source Code:
src/gaia/llm/__init__.py- Package exportssrc/gaia/llm/base_client.py- Abstract interfacesrc/gaia/llm/factory.py- Client factorysrc/gaia/llm/providers/- Provider implementations
Primary API:
create_client() factory function
Module: gaia.llm
Imports:from gaia.llm import create_client(preferred)from gaia.llm import LLMClient, NotSupportedError
Overview
The LLM client package provides a unified interface for generating text from multiple LLM backends using a provider pattern. Each provider implements the abstractLLMClient interface, with optional methods raising NotSupportedError when unavailable.
Key Features:
- Factory-based client creation with
create_client() - Two providers: Lemonade (local AMD-optimized, plus models configured behind Lemonade such as on-prem gateways) and Claude
- Abstract base class for type safety and extensibility
- Graceful handling of unsupported features via
NotSupportedError - Streaming and non-streaming generation
- Backward-compatible
use_claudeflag
Methods marked with ✗ raise
NotSupportedError when called on that provider.
Cloud models served through Lemonade have their own capabilities; selecting
Lemonade does not imply that every remote model supports every operation.Removed adapters and migration
The directopenai and litellm adapters were removed because they discarded
native tool calls. The litellm installation extra is removed too. The
openai Python dependency remains: Lemonade uses it for compatible HTTP requests.
provider="openai", provider="litellm", and use_openai=True raise ValueError
with migration guidance before importing a provider or issuing requests.
use_chatgpt=True in the agent, chat/audio/talk SDK chain and the legacy
--use-chatgpt CLI flag also fail explicitly. These flags are retained only as
migration-error shims; they do not select another backend or ignore the setting.
Configure the upstream model in Lemonade, then pass the Lemonade server URL and
its catalog model ID. Do not substitute a raw upstream endpoint for Lemonade’s
URL: a generic OpenAI-compatible service does not implement Lemonade’s catalog
and lifecycle API. See gateway migration.
Historical release notes describe the providers that shipped in those releases.
Requirements
Functional Requirements
-
Factory Pattern
create_client()factory function for client creation- Explicit provider selection via
providerparameter (“lemonade”, “claude”) - Backward-compatible
use_claudeflag - Auto-detection of provider from flags when
providernot specified - Default to Lemonade provider when no flags set
- Retired names (
"openai","litellm") and a trueuse_openaiflag raiseValueErrorwith migration guidance before any provider is imported
-
Abstract Interface
LLMClientABC defines unified interfaceprovider_nameproperty returns provider name- Required methods (all providers must implement):
generate()- Text completionchat()- Chat completion with message history
- Optional methods (raise
NotSupportedErrorif not implemented):embed()- Generate embeddingsvision()- Vision/image understandingget_performance_stats()- Performance statisticsload_model()- Load a modelunload_model()- Unload current model
-
Provider Implementations
- LemonadeProvider: Full support for all methods, connects to local Lemonade server
- ClaudeProvider:
generate,chat,vision,get_performance_stats(last-call usage) - All providers support streaming and non-streaming modes
-
Error Handling
NotSupportedErrorraised for unsupported methods- Clear error messages indicating provider and unsupported method
- Connection errors handled by underlying provider implementations
Non-Functional Requirements
-
Performance
- Lazy provider loading via
importlib(load only when needed) - Minimal overhead from abstraction layer
- Streaming support across all providers
- Local models run with their model card’s sampling, else temperature 0.1 with penalties; cloud models keep the client default
- Lazy provider loading via
-
Reliability
- Type safety through ABC pattern
- Graceful handling of unsupported features
- Clear error messages for provider capabilities
- Provider-specific connection management
-
Usability
- Simple factory function interface
- Backward compatibility with existing code
- Consistent API across all providers
- Clear documentation with examples
API Specification
Package Structure
Package Exports (__init__.py)
VLMClient is also re-exported from gaia.llm — see
vlm-client for its API.
Factory Function (factory.py)
Abstract Base Class (base_client.py)
NotSupportedError (exceptions.py)
Provider Implementations
LemonadeProvider (providers/lemonade.py)
Full feature support - implements all methods.
ClaudeProvider (providers/claude.py)
Partial support - generate, chat, vision, get_performance_stats.
Implementation Details
Provider Selection Logic
The factory function auto-detects the provider based on parameters:Lazy Provider Loading
Providers are loaded dynamically usingimportlib to avoid importing unnecessary dependencies:
NotSupportedError Pattern
Optional methods raiseNotSupportedError by default in the ABC:
Sampling Defaults
A local model whose card publishes sampling settings runs with them. These live inMODEL_SAMPLING_PROFILES in lemonade_client.py, keyed by Lemonade model id. For example,
Qwen3-30B-A3B-Instruct-2507-GGUF gets temperature=0.7, top_p=0.8, top_k=20,
min_p=0 and presence_penalty=1.0, per its
model card. A card that gives
separate thinking and non-thinking profiles registers both. The thinking mode comes from
requested_thinking(): the caller’s chat_template_kwargs={"enable_thinking": ...} when it
sets one, else GAIA’s choice for the model (ModelRequirement.thinking). The provider picks
the sampling profile from it and LemonadeClient.chat_completions sends it as the switch, so
the sampling always matches the mode the model runs in.
Qwen3.6-35B-A3B-GGUF runs with thinking on
and gets its card’s thinking profile for coding and precise work. Memory’s short JSON side
calls (extraction, consolidation, reconciliation, skill distillation) pass
no_thinking_kwargs(model), which turns thinking off for such a model: reasoning is billed
against max_tokens, so with it on they reason to the cap and return no answer.
Every other local model gets LOCAL_SAMPLING_DEFAULTS: temperature=0.1 plus frequency,
presence and repeat penalties, so it does not loop on tables and paragraphs. Cloud models get
neither, because near-greedy sampling sends a reasoning model’s thinking into a runaway. They
keep the client default (0.7). Any sampling argument the caller passes is sent as given.
top_k, min_p, repeat_penalty and repeat_last_n are llama.cpp-native. When streaming,
they travel in the OpenAI SDK’s extra_body and land at the top level of the request body.
Provider-Specific Implementation
LemonadeProvider wraps the low-levelLemonadeClient:
Native tool-call transport
The shared agent consumes the provider’s string response. Lemonade preserves native calls in the__tool_calls__ sentinel envelope, including call IDs,
function names and arguments; it does not replace a tool-only response with empty
assistant text. Streaming deltas are accumulated before dispatch so a partial
argument fragment cannot execute as a complete call. The agent turns results back
into the corresponding tool messages for the next model request.
Provider usage is available through get_last_usage() when the backend reports
it. Missing usage is not proof of zero tokens or zero cost. Per-turn timing and
usage records are owned by agents/base/turn_metrics.py.
Error boundaries
Configuration errors fail before inference. Lemonade transport errors are classified by the Lemonade provider into typed failures with user-facing guidance. Authentication and upstream service failures must remain attributable to the configured destination; no implicit retry with a different model or provider is permitted. Optional dependencies must not be required merely to reject a removed provider name.Testing Requirements
Unit Tests
File:tests/unit/test_llm_client_factory.py
tests/unit/test_removed_llm_providers.py — retired names and flags are
rejected across the factory, SDK, base agent and CLI, before provider import or
model initialization.
Regression coverage
test_llm_client_factory.py: supported selection and shared interface.test_removed_llm_providers.py: rejected legacy names and flags across the factory, SDK, base agent and CLI, before model initialization.unit/test_lemonade_client_http.py: supported Lemonade operations and their request shapes, against mocked HTTP.test_lemonade_client.py: the same operations against a live Lemonade Server.test_lemonade_cloud_models.py: local/cloud lifecycle separation.test_parallel_tool_calls.py: preservation and execution of native calls.
Integration Tests
File:tests/integration/test_llm_providers.py
Dependencies
Required Packages
Import Dependencies
Factory (factory.py):
base_client.py):
providers/lemonade.py):
providers/claude.py):
Usage Examples
Example 1: Basic Usage with Factory
Example 2: Explicit Provider Selection
Example 3: Handling Unsupported Features
Example 4: Chat with Message History
Example 5: Streaming Responses
Example 6: Embeddings (Lemonade only)
Example 7: Vision (Lemonade and Claude only)
Example 8: Model Management (Lemonade only)
Example 9: Remote Lemonade Server
Example 10: System Prompts
Third-Party LLM Integration
Inference Endpoints
GAIA sends inference requests in the OpenAI-compatible shapes below.Completions Endpoint
Default:
POST /v1/completionsUsed for pre-formatted promptsChat Completions Endpoint
POST /v1/chat/completionsUsed for structured conversations with message historyCompletions Endpoint
- Request
- Response
- Streaming
Chat Completions Endpoint
- Request
- Response
- Streaming
Configuration
Point GAIA at the Lemonade server that fronts your model:- Environment Variable
- Direct Initialization
Linux
Windows (PowerShell)
Windows (CMD)
URL Normalization: LemonadeClient automatically appends
/api/v1 if not present:http://localhost:8080→http://localhost:8080/api/v1- If your server uses
/v1instead, provide the full path:http://localhost:8080/v1
Example Integration
Troubleshooting
Connection Errors
Connection Errors
Problem: Requests fail because the server can’t be reached (connection refused, DNS, or TLS)Solutions:
- Verify the server is running:
- Check firewall settings
- Ensure correct base URL format
- Test with explicit base URL:
404 Endpoint Errors
404 Endpoint Errors
Problem: Requests fail with HTTP 404Solutions:
- Verify API path structure:
/v1vs/api/v1 - Confirm
base_urlpoints at the Lemonade server, not the raw upstream endpoint - Use chat method explicitly if needed:
Model Not Found
Model Not Found
Problem: Model errors or “model not loaded”Solutions:
- Specify model explicitly:
- List the models the server exposes:
- Use the exact model ID from that catalog
Streaming Issues
Streaming Issues
Problem: Streaming responses not workingSolutions:
- Verify the server supports Server-Sent Events (SSE)
- Check Content-Type headers:
text/event-stream - Test non-streaming first:
- Enable debug logging:
Documentation Updates Required
docs/sdk/sdks/llm.mdx
Add to LLM Section:LLMClient Technical Specification