feat: add LiteLLM as LLM provider#119
Conversation
|
cc @chauncygu |
|
Hi @RheagalFire, thanks for the PR. A few blockers before this can merge:
Smaller items: live E2E results in the PR body aren't in the test suite (please add a skipif-gated Direction is good — fix blockers 1–4 and I'm happy to merge. Thanks! |
…ull entry in docs/news.md - README News: one-paragraph May 12 entry summarising what PR #119 shipped, what the follow-up fixed (dep classification, ledger, streaming, registry wiring), and pointing to docs/news.md. - docs/news.md: long-form entry covering motivation, the four integration gaps the original PR left open, the implementation of each fix, the five additional bugs caught in self-review, test count delta (12 → 23 unit + 3 e2e), full-suite numbers, and the doc surface added in this branch. "(latest)" marker moved off the May 11 daemon F-4 entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Hi @RheagalFire, Thanks for your great contributions. I have merged and fixed the issues. Thanks. |
…fix ledger, wire into providers.py Addresses the upstream review blockers on PR SafeRL-Lab#119: - Move litellm from core deps to [project.optional-dependencies] under the `litellm` extra, and add to `all`. PR SafeRL-Lab#119's body said it was optional but the diff put it in core, forcing every install to pull litellm's transitive chain. - Lazy-import the SDK from inside LiteLLMProvider so the module stays importable on machines without litellm installed (matches the AnthropicProvider contract; verified via test that runs in a dev env without litellm installed). - Wire `litellm` into both user-facing paths: • cc_kernel/runner/llm/__main__.py:_select_provider gains a `litellm` branch so CC_LLM_PROVIDER=litellm reaches the runner. • Top-level providers.PROVIDERS gains a `litellm` entry and a new stream_litellm() generator so the CLI / Web UI can resolve --model litellm/<provider>/<model>. Without this, no end-to-end caller could reach the new class. - Populate cost_micro via litellm.completion_cost (was hard-coded 0, silently zeroing every charge through this path). When pricing isn't available, set metadata['cost_unknown']=True so the ledger can tell an unpriced model apart from a real $0 (Ollama, free NIM tier). - Reassemble streaming chunks via litellm.stream_chunk_builder with stream_options={"include_usage": True} so the final response carries token counts, tool_calls, and the real finish_reason. Streaming previously dropped all three, breaking the RFC 0022 multi-iteration tool-call loop. - Map litellm.exceptions.{AuthenticationError, BadRequestError, NotFoundError, UnsupportedParamsError} to ProviderInvalidRequest instead of swallowing every error into ProviderUnavailable. - Defensive tool_call parsing: skip malformed entries (missing `function`, empty `name`) and coerce JSON-valid-but-non-dict arguments (e.g. "null", "[1,2]") to {} so a single broken tool_call no longer crashes the entire response via LlmResponse validation. - Factor message-building into _build_messages / _build_params so __call__ and stream() no longer duplicate ~30 lines. - Surface litellm_provider and actual_model in response metadata to aid cross-provider debugging. - Add tests/e2e_litellm_provider.py (3 live-API tests, skipif-gated on CC_LITELLM_E2E=1 + per-provider credentials). - Make test_litellm_in_requirements cwd-agnostic by resolving paths from __file__ rather than Path("requirements.txt"). - Add docs/guides/recipes.md section explaining when to prefer litellm/<provider>/<model> over custom/ — Bedrock SigV4, Azure deployment routing, Vertex AI service-account JWTs are the value-add. Tests: 29 unit tests in test_litellm_provider.py (was 12), 3 e2e in e2e_litellm_provider.py. Full non-e2e suite: 2222 passed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
LiteLLMProvideras a new LLM adapter incc_kernel/runner/llm/, enabling access to 100+ providers (OpenAI, Anthropic, Google, Azure, Bedrock, Ollama, etc.) via a single unified SDKProviderprotocol asAnthropicProvider:__call__(LlmRequest) -> LlmResponse+stream(LlmRequest, on_delta) -> LlmResponsepip install cheetahclaws[litellm]Changes
cc_kernel/runner/llm/litellm_provider.py- newLiteLLMProviderwith:litellm.completion()withdrop_params=Truestream()withon_deltacallback for streaming text deltas{id, name, input}formatpyproject.toml- addedlitellmoptional dependency (pip install cheetahclaws[litellm]), also included inallextrarequirements.txt- addedlitellm>=1.60.0,<2.0.0tests/test_litellm_provider.py- 12 unit tests (all passing)Tests
Unit tests (12/12 passing):
Live E2E tests (3/3 passing against real API):
Example usage
See https://docs.litellm.ai/docs/providers for 100+ supported model strings.
Impact
AnthropicProvideruntouchedProviderprotocol (__call__+stream)ProviderUnavailable,ProviderInvalidRequest)litellmis an optional dependency (pip install cheetahclaws[litellm])drop_params=Truesilently drops provider-unsupported kwargs