feat(litellm): add experimental Switchyard integration - #182
Conversation
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
Signed-off-by: Dhruv Nandakumar <168006707+dnandakumar-nv@users.noreply.github.com>
WalkthroughChangesAdds an experimental LiteLLM integration that routes normalized Switchyard requests through a Dockerized LiteLLM gateway to OpenRouter-backed aliases. It includes the client adapter, weighted routing examples, benchmark configuration, documentation, and offline or opt-in Docker E2E tests. LiteLLM integration
Estimated code review effort: 4 (Complex) | ~45 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
examples/experimental/litellm/tests/test_e2e.py (1)
25-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument the public fixture.
Add a concise docstring describing its opt-in behavior, yielded URL, skips, and Compose failure behavior.
Proposed fix
`@pytest.fixture`(scope="session") def litellm_base_url() -> Iterator[str]: + """Yield a loopback LiteLLM URL for opt-in paid E2E tests. + + Skips without the opt-in, OpenRouter key, or Docker; raises on Compose failures. + """ if os.environ.get("SWITCHYARD_LITELLM_E2E") != "1":As per coding guidelines, “Add concise triple-quoted docstrings for public functions, classes, methods, and API entry points.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/litellm/tests/test_e2e.py` around lines 25 - 26, Document the public litellm_base_url fixture with a concise triple-quoted docstring covering its opt-in behavior, the URL it yields, when tests are skipped, and how Docker Compose failures are handled.Source: Coding guidelines
examples/experimental/litellm/tests/test_client.py (1)
135-191: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a
tool_choicerejection test case.The parametrize list covers most
_payloadvalidation branches but omitstool_choice, which_payloadexplicitly rejects when non-None(perclient.py'sif request.get("tool_choice") is not None: raise ValueError("tool_choice is not supported")). Add a case like(lambda body: body.update(tool_choice="auto"), "tool_choice")to guard this branch against regression.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@examples/experimental/litellm/tests/test_client.py` around lines 135 - 191, Add a parameterized rejection case to the test list covering `_payload`’s unsupported tool_choice branch: mutate the body with a non-None tool_choice value such as "auto" and expect the validation match to identify "tool_choice". Keep the existing validation cases unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/experimental/litellm/pyproject.toml`:
- Around line 27-28: Add a py.typed marker file under the src/switchyard_litellm
package so installed consumers recognize its inline type information. Ensure the
marker is included in the setuptools package data produced by the existing
package discovery configuration.
In `@examples/experimental/litellm/tests/test_e2e.py`:
- Around line 49-61: Bound both Docker Compose lifecycle calls in the E2E setup
around the startup and teardown subprocess.run invocations: add a finite
--wait-timeout argument to the compose up command and timeout= values to both
subprocess.run calls, ensuring startup and cleanup cannot hang indefinitely.
---
Nitpick comments:
In `@examples/experimental/litellm/tests/test_client.py`:
- Around line 135-191: Add a parameterized rejection case to the test list
covering `_payload`’s unsupported tool_choice branch: mutate the body with a
non-None tool_choice value such as "auto" and expect the validation match to
identify "tool_choice". Keep the existing validation cases unchanged.
In `@examples/experimental/litellm/tests/test_e2e.py`:
- Around line 25-26: Document the public litellm_base_url fixture with a concise
triple-quoted docstring covering its opt-in behavior, the URL it yields, when
tests are skipped, and how Docker Compose failures are handled.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: c6ae4b14-8a1b-4bae-8f6c-6f075ec5166a
⛔ Files ignored due to path filters (1)
examples/experimental/litellm/uv.lockis excluded by!**/*.lock
📒 Files selected for processing (16)
docs/routing_algorithms/random_routing.mdexamples/experimental/litellm/.env.exampleexamples/experimental/litellm/README.mdexamples/experimental/litellm/benchmark-route.yamlexamples/experimental/litellm/benchmark-tasks.txtexamples/experimental/litellm/compose.yamlexamples/experimental/litellm/example.pyexamples/experimental/litellm/litellm-config.yamlexamples/experimental/litellm/pyproject.tomlexamples/experimental/litellm/src/switchyard_litellm/__init__.pyexamples/experimental/litellm/src/switchyard_litellm/client.pyexamples/experimental/litellm/tests/conftest.pyexamples/experimental/litellm/tests/test_client.pyexamples/experimental/litellm/tests/test_e2e.pyexamples/experimental/litellm/tests/test_gateway_config.pyexamples/experimental/litellm/tests/test_random_routing.py
nachiketb-nvidia
left a comment
There was a problem hiding this comment.
lgtm for the example and first pass, we'll come back to this once we have changes to benchmarking and binding for better algos
What
Add an experimental, source-installable
switchyard-litellmpackage underexamples/experimental/litellmthat demonstrates how to combine Switchyardrouting with a Dockerized LiteLLM gateway backed by OpenRouter.
LiteLLMSyClient, a buffered text-only adapter from normalized libsydictionaries to LiteLLM's asynchronous Completion API (
acompletion).switchyard.libsy.algorithms.randombinding betweenopenai/gpt-5.6-sol(strong) andmoonshotai/kimi-k3(fast).OPENROUTER_API_KEYbehind LiteLLM gatewayaliases so application code only selects
strongorfast.ghcr.io/berriai/litellm:v1.92.0andlitellm==1.92.0.OpenRouter models, and a three-task Harbor smoke benchmark configuration.
startup, application usage, testing, benchmarking, limitations, and security.
Why
LiteLLM provides the OpenAI-compatible gateway, provider integration, model
aliases, and credential boundary. Switchyard owns the routing decision. This
example connects the two with installable code and copyable configuration so a
developer can add Switchyard routing without embedding provider-specific model
IDs or credentials in application code.
How tested
uv run ruff check .cleanuv run mypy switchyardclean — 150 source filesuv run pytest tests/ -vgreen — 1,723 passed, 35 skippedstrongandfastaliases passed; isolated Compose teardown verifiedrequests, 0 errors,
strong=7,fast=5and secret-pattern audit
Checklist
switchyard_litellm.__init__; no root Switchyard API change is intended.the random-routing documentation.
Notes for reviewers
the top and documents the supported request subset and security boundary.
OPENROUTER_API_KEYandSWITCHYARD_LITELLM_E2E=1; merely having a key exported does not spend.acompletionwith retries disabled so retry androuting policy remain with the outer Switchyard layer.
tools, media, structured output, and streaming fail explicitly.
Codex model-catalog schema mismatch without changing benchmark source.
Summary by CodeRabbit
New Features
Documentation
Tests