LiteLLM Provider
File:src/cofounder_agent/services/llm_providers/litellm_provider.py
Tested by: smoke-tested against local Ollama 2026-05-04; unit tests pending
Last reviewed: 2026-05-23
What it does
LiteLLMProvider is an LLMProvider plugin (under plugins.llm_provider.LLMProvider) backed by the LiteLLM SDK. It is the primary LLM router on prod for all four cost tiers as of 2026-05-16 (plugin.llm_provider.primary.{free,budget,standard,premium}='litellm'). Provider routing, retries-with-backoff, and authoritative cost tracking are delegated to mature OSS. The legacy services/model_router.py + usage_tracker.py + model_constants.py trio was deleted 2026-05-08 in the Phase 2 cleanup.
Three public methods, all async, mirroring the LLMProvider Protocol:
complete(messages, model, **kwargs)— non-streaming chat completion. Returns aCompletion(text, model, prompt_tokens, completion_tokens, total_tokens, finish_reason, raw). Therawdict surfacesresponse_costwhen LiteLLM’s MODEL_COSTS table knows the model, socost_logscan write the authoritative number without re-deriving prices.stream(messages, model, **kwargs)— streaming chat. YieldsToken(text, finish_reason)per chunk. Same call signature ascomplete; just setsstream=Trueinternally.embed(text, model)— embedding generation vialitellm.aembedding. Returnslist[float]. Same model namespace ascomplete(ollama/nomic-embed-textetc).
Activation
The plugin sits alongsideOllamaNativeProvider and OpenAICompatProvider in plugins/registry.py’s core samples. As of 2026-05-16 all four plugin.llm_provider.primary.{free,budget,standard,premium} rows are set to 'litellm' on prod — this is the canonical state. To revert a tier to the legacy native provider (e.g. for a focused regression test), an operator flips one row back:
kwargs['_provider_config'] from the dispatcher.
Model namespace
LiteLLM prefixes provider on the model string. The provider auto-prefixes bare names so existing callers don’t churn:| Caller passes | Provider sends |
|---|---|
gemma3:27b | ollama/gemma3:27b (default_prefix='ollama/') |
ollama/glm-4.7-5090:latest | passthrough |
openai/gpt-4o-mini | passthrough |
anthropic/claude-haiku-4-5 | passthrough |
vertex_ai/gemini-2.0-flash | passthrough |
openrouter/anthropic/claude-haiku-4-5 | passthrough |
http://host:port/v1 | passthrough (custom api_base) |
drop_params=true (default) strips kwargs the target backend doesn’t recognize so a single call signature works across backends. Per-call timeout_s overrides the provider default.
Reads from / writes to
- Reads:
_provider_configkwargs from the dispatcher (api_base,timeout_seconds,drop_params,default_prefix,allow_paid_base_url,model_api_base_overrides); ENV vars only via LiteLLM’s own config surface — the plugin doesn’t read os.environ directly perfeedback_no_env_vars. The paid-endpoint gateallow_paid_base_urlreaches the provider via that injected config: the dispatcher’sget_provider_configfolds the flatplugin.llm_provider.litellm.allow_paid_base_urlrow (the operator-facing key the seed + refusal messages reference) into the config as a fallback, so a value in the nestedconfigblob or the flat row both take effect — nested wins when both are set. - Writes: nothing back to Postgres. Cost logging is the dispatcher’s job; the plugin just exposes
response_coston theCompletion.rawdict for the dispatcher to consume. - External APIs: whatever LiteLLM speaks — Ollama, OpenAI, Anthropic, Gemini, vLLM, llama.cpp, OpenRouter, Bedrock, Vertex. Per
feedback_no_paid_apis, the OSS distribution defaults to Ollama viadefault_prefix='ollama/'; cloud providers stay opt-in behindcost_guard.
Failure modes
litellmnot installed —import litellmraises ImportError at first call. Operators who explicitly opt out of LiteLLM should flipplugin.llm_provider.primary.{tier}back toollama_nativeper tier; the worker image shipslitellmby default since it’s the prod router.acompletionraises — exception propagates with full traceback after alogger.exception(). Caller (the dispatcher) decides whether to fall back to the next provider in the chain.- Empty response —
text=''andfinish_reason=''; caller sees a successful Completion with no content. Surfaces as a quality-validator failure downstream rather than a hard error. - Cost table miss — LiteLLM doesn’t know the model’s price;
response_costis absent fromrawandcost_logsrecords0.0. Not a fatal condition; surfaces as missing cost data on the Grafana cost panel.
Cleanup status
Phase 2 of poindexter#199 landed 2026-05-08:services/model_router.py (~580 LOC), services/usage_tracker.py (~295 LOC), and services/model_constants.py were all deleted. services/cost_guard.py was retained as a thin budget-cap + energy-tracking wrapper. LiteLLM owns provider routing, cost tracking, and rate-limiting; the hand-rolled stack is gone.
See also
model_router.md— stub redirect (the file was deleted 2026-05-08).plugins/llm_provider.py— theLLMProviderProtocol this plugin implements.plugins/registry.py— whereLiteLLMProvideris registered alongsideOllamaNativeProviderandOpenAICompatProvider.../cost-tier-routing.md— the per-step*_modelpins that select the model passed to these provider plugins (thecost_tier.*tier→model API was removed in PR #1907; the tier→provider axisplugin.llm_provider.primary.<tier>remains).feedback_no_paid_apis(operator design note) — local-default policy.feedback_no_wheel_reinvention(operator design note) — adoption rationale.