-
Notifications
You must be signed in to change notification settings - Fork 0
LLM Providers and BYOK
Maestro is provider-agnostic. Every LLM provider is an adapter class behind a common interface, so adding a provider means adding one file — never modifying existing code. Users bring their own keys (BYOK), which are encrypted at rest and never returned to the browser. The framework lives in backend/app/services/llm_service.py.
-
LLMAdapter— base class.AdapterCapabilitiesdeclares what a provider supports (native tool-calling, native JSON schema, streaming). -
_OpenAICompatAdapter— shared implementation for the many OpenAI-compatible providers. -
ChatMessage,ToolCall,ToolDef,LLMResponse,StreamEvent,LLMError— the common data types. - Retries via Tenacity;
_is_retryabletreats 5xx + transport errors as transient, but not 4xx or read-timeouts.
All are BYOK-selectable as the "brain" of a task:
ollama, openai, anthropic, gemini, groq, deepseek, mistral, xai, openrouter, together, perplexity, custom.
Concrete adapters: OllamaAdapter, OpenAIAdapter, GeminiAdapter, GroqAdapter, DeepSeekAdapter, MistralAdapter, XAIAdapter, OpenRouterAdapter, TogetherAdapter, PerplexityAdapter, CustomOpenAICompatAdapter (SSRF-guarded), and AnthropicAdapter (the real Messages API: x-api-key, system, max_tokens).
LLM_CHAT_PROVIDERS in constants.py is the authoritative list of the 12.
BYOK also stores keys for service connectors used by tools/integrations, not as a chat brain: x, github, instagram, google_maps, slack, notion, discord, telegram.
Adapters are wrapped in layers, each adding one concern:
-
FallbackLLMAdapter— tries Gemini, falls back to Ollama per call. This is what makes the free/local tier resilient. -
TokenMeter— counts tokens for every LLM call (routing, planning, subagent, reviewer, synthesis) via a shared_TokenCounter, with estimation when the provider doesn't report usage. This is what feeds the quota ledger (see Billing-and-Quota). -
TracedAdapter— emits OTel-shapedgen_ai.*spans + cost, sitting underTokenMeter. -
AdapterPool— resolves the model per agent role (ctx.role_adapter(role)) usingresolve_model: precedence is explicit override > user preference > provider tier default. All roles share one token counter.
-
structured_call(agents/structured.py) — a schema-validated LLM call. It uses nativejson_schemawhen the provider supports it, otherwise falls back toextract_json+ Pydantic validation, retrying on mismatch. -
Native tool loop — used when
capabilities.native_toolsis true (parses/serializes OpenAI-styletool_calls). -
Directive loop — the provider-agnostic fallback: the model emits a JSON
ToolDirective, parsed bytools.parse_directive. This lets even a bare completion endpoint use tools.
See Agent-Orchestration for how subagents drive these loops.
constants.py holds MODEL_TIER_DEFAULTS, PROVIDER_TIER_MODELS, PROVIDER_COST_PER_1K_TOKENS, and MODEL_PRICING. Per-user overrides live in users.model_preferences (JSONB), settable via PATCH /users/me and consumed by AdapterPool.
embed_texts uses nomic-embed-text via Ollama. The endpoint is EMBEDDING_ENDPOINT when set, otherwise falls back to FREE_MODEL_ENDPOINT. Dimension is EMBEDDING_DIM = 768. In production, embeddings hit a small dedicated ollama service (embeddings only). See RAG-and-Memory and Configuration.
- Keys are encrypted with AES-256-GCM (
core/security.pyencrypt_secret): output isbase64(12-byte nonce ‖ ciphertext). The master key (API_KEY_MASTER_KEY) is base64→32-byte and lives only in the environment. - The same master key encrypts the user's TOTP secret.
- API keys are never returned to the frontend — only
provider,label, and akey_hint(****abcd) are exposed. See Security. - A resumed durable task re-decrypts the key from Postgres at run time; the frozen run payload contains no secret. See Agent-Orchestration.
- Custom endpoints pass through the SSRF guard (
url_guard.check_public_url) before any request.
- Add the provider to the
LLMProviderenum andLLM_CHAT_PROVIDERS(if chat-capable) inconstants.py. - Add a concrete adapter class in
llm_service.py(subclass_OpenAICompatAdapterif OpenAI-compatible, else implementLLMAdapter). - Register it in
get_adapter. - Add tier/pricing entries if you want cost tracking.
No existing adapter, wrapper, or agent code changes. This is the pattern the whole platform is built on. See Contributing-and-License.
Maestro — source repository · Sustainable Use License v1.0 · This wiki documents the current code; where it differs from README.md, the wiki is authoritative.
Overview
Backend
- Backend-Reference
- API-Reference
- Database-Schema
- LLM-Providers-and-BYOK
- Security
- Billing-and-Quota
- RAG-and-Memory
- Realtime-and-WebSockets
Frontend
Operations
Project