Drops the src/providers/ package (base class, AnthropicProvider, OpenAIProvider, factory) in favour of a single src/llm.py that calls litellm.completion() directly. litellm handles provider routing, authentication, and SDK differences for 100+ providers without any code we need to maintain. Changes: - Delete src/providers/ entirely - Add src/llm.py — one complete() function wrapping litellm - src/agent/core.py: EmailAgent takes model: str instead of LLMProvider - src/config.py: ai_provider + api key fields → single ai_model string in litellm format (e.g. "anthropic/claude-opus-4-6") - main.py: remove provider factory wiring; pass config.ai_model to agent - .env.example: simplify AI section, show litellm model string examples - pyproject.toml: replace anthropic + openai deps with litellm>=1.0.0 - uv.lock: regenerated https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
23 lines
887 B
Python
23 lines
887 B
Python
"""LLM completion via litellm — supports any provider with a single call."""
|
|
|
|
import litellm
|
|
|
|
|
|
def complete(model: str, system: str, messages: list) -> str:
|
|
"""Call any LLM and return the response text.
|
|
|
|
Args:
|
|
model: litellm model string, e.g. "anthropic/claude-opus-4-6" or
|
|
"openai/gpt-4o". The matching API key must be set as an
|
|
environment variable (ANTHROPIC_API_KEY, OPENAI_API_KEY, …).
|
|
system: System prompt text.
|
|
messages: List of objects with .role and .content attributes.
|
|
|
|
Returns:
|
|
The model's reply as a plain string.
|
|
"""
|
|
api_messages = [{"role": "system", "content": system}]
|
|
api_messages += [{"role": m.role, "content": m.content} for m in messages]
|
|
response = litellm.completion(model=model, messages=api_messages, max_tokens=2048)
|
|
return response.choices[0].message.content
|