From 9f910269d0de25f85cda5b745c600b9e138c04c2 Mon Sep 17 00:00:00 2001 From: RheagalFire Date: Fri, 12 Jun 2026 01:24:50 +0530 Subject: [PATCH 1/2] feat: add LiteLLM support via litellm: model prefix --- pyproject.toml | 3 +++ timecopilot/agent.py | 30 +++++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b9682d22..b523f474 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -121,6 +121,9 @@ distributed = [ "pyspark<4.1", "ray==2.48", ] +litellm = [ + "litellm>=1.80.0,<1.87.0", +] [project.scripts] timecopilot = "timecopilot._cli:main" diff --git a/timecopilot/agent.py b/timecopilot/agent.py index f24e0535..d690d23d 100644 --- a/timecopilot/agent.py +++ b/timecopilot/agent.py @@ -8,6 +8,7 @@ from pydantic_ai import Agent, ModelRetry, RunContext from pydantic_ai.agent import AgentRunResult from pydantic_ai.models import Model +from pydantic_ai.models.openai import OpenAIModel from rich.console import Console from rich.panel import Panel from rich.table import Table @@ -34,6 +35,33 @@ from .forecaster import Forecaster, TimeCopilotForecaster from .models.adapters.sktime import SKTimeAdapter + + +def _resolve_llm(llm: str | Model) -> str | Model: + """Resolve LLM string, adding LiteLLM support for 100+ providers. + + If the string starts with 'litellm:', creates a pydantic-ai OpenAI model + pointed at a running LiteLLM proxy. Set LITELLM_BASE_URL to your proxy + address (default: http://localhost:4000/v1). + + Examples: + --llm litellm:anthropic/claude-sonnet-4-6 + --llm litellm:groq/llama-3.3-70b-versatile + --llm litellm:deepseek/deepseek-chat + """ + if not (isinstance(llm, str) and llm.startswith("litellm:")): + return llm + + import os + + from openai import AsyncOpenAI + + model_name = llm[len("litellm:"):] + base_url = os.environ.get("LITELLM_BASE_URL", "http://localhost:4000/v1") + api_key = os.environ.get("LITELLM_API_KEY", "sk-unused") + + client = AsyncOpenAI(api_key=api_key, base_url=base_url) + return OpenAIModel(model_name, openai_client=client) from .models.prophet import Prophet from .models.stats import ( ADIDA, @@ -541,7 +569,7 @@ def __init__( "model is not allowed to be passed as a keyword argument" "use `llm` instead" ) - self.llm = llm + self.llm = _resolve_llm(llm) self.forecasting_agent = Agent( deps_type=ExperimentDataset, From efc016bc26cce7f0bbdd9f016d1ab1c542bd74f7 Mon Sep 17 00:00:00 2001 From: RheagalFire Date: Fri, 12 Jun 2026 01:29:15 +0530 Subject: [PATCH 2/2] fix: use litellm SDK directly instead of proxy --- timecopilot/agent.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/timecopilot/agent.py b/timecopilot/agent.py index d690d23d..0e14203f 100644 --- a/timecopilot/agent.py +++ b/timecopilot/agent.py @@ -41,8 +41,8 @@ def _resolve_llm(llm: str | Model) -> str | Model: """Resolve LLM string, adding LiteLLM support for 100+ providers. If the string starts with 'litellm:', creates a pydantic-ai OpenAI model - pointed at a running LiteLLM proxy. Set LITELLM_BASE_URL to your proxy - address (default: http://localhost:4000/v1). + backed by litellm SDK (no proxy needed). LiteLLM reads provider API keys + from environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.). Examples: --llm litellm:anthropic/claude-sonnet-4-6 @@ -52,15 +52,17 @@ def _resolve_llm(llm: str | Model) -> str | Model: if not (isinstance(llm, str) and llm.startswith("litellm:")): return llm - import os - - from openai import AsyncOpenAI - model_name = llm[len("litellm:"):] - base_url = os.environ.get("LITELLM_BASE_URL", "http://localhost:4000/v1") - api_key = os.environ.get("LITELLM_API_KEY", "sk-unused") - - client = AsyncOpenAI(api_key=api_key, base_url=base_url) + try: + import litellm + + litellm.drop_params = True + client = litellm.AsyncOpenAI() + except ImportError: + raise ImportError( + "litellm package required for litellm: models. " + "Install with: pip install 'timecopilot[litellm]'" + ) return OpenAIModel(model_name, openai_client=client) from .models.prophet import Prophet from .models.stats import (