feat(libsy): add minimal Python run API#95
Conversation
Signed-off-by: nachiketb <nachiketb@nvidia.com>
ced9e28 to
13590af
Compare
Signed-off-by: nachiketb <nachiketb@nvidia.com>
13590af to
8bf53fb
Compare
WalkthroughThe change adds Rust-backed ChangesLibsy Python bindings
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 (1)
crates/switchyard-py/src/libsy_bindings.rs (1)
175-177: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDocument why Python errors are erased here.
This helper intentionally discards the original
PyErrtype and traceback to cross theBoxErrorboundary; document that behavior and its later conversion toLibsyError.As per coding guidelines, add concise Rust comments or
///documentation for non-obvious private helpers.🤖 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 `@crates/switchyard-py/src/libsy_bindings.rs` around lines 175 - 177, Document the private helper boxed_python_error with a concise Rust comment explaining that it erases the original PyErr type and traceback when crossing the BoxError boundary, and that the resulting error is later converted to LibsyError.Source: Coding guidelines
🤖 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 `@crates/switchyard-py/src/libsy_bindings.rs`:
- Around line 82-90: Update LlmTarget::new in
crates/switchyard-py/src/libsy_bindings.rs (lines 82-90) to validate that
client.call is asynchronous and accepts the async call(request, *, target)
contract, rejecting incompatible implementations during construction. Add
regression tests in tests/test_libsy_minimal_bindings.py (lines 77-82) covering
both a synchronous callable and a callable with an incompatible signature.
In `@switchyard_rust/libsy.py`:
- Around line 15-18: Preserve LibsyError’s SwitchyardRuntimeError type across
both typing surfaces: in switchyard_rust/libsy.py lines 15-18, type-import
SwitchyardRuntimeError and annotate LibsyError as type[SwitchyardRuntimeError];
in switchyard_rust/libsy.pyi line 17, import SwitchyardRuntimeError and declare
LibsyError as inheriting from it.
---
Nitpick comments:
In `@crates/switchyard-py/src/libsy_bindings.rs`:
- Around line 175-177: Document the private helper boxed_python_error with a
concise Rust comment explaining that it erases the original PyErr type and
traceback when crossing the BoxError boundary, and that the resulting error is
later converted to LibsyError.
🪄 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: 142efe86-56f1-4c3e-89e1-42b225cd0d6f
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock,!Cargo.lock
📒 Files selected for processing (11)
crates/libsy-protocol/src/llm.rscrates/switchyard-py/Cargo.tomlcrates/switchyard-py/src/errors.rscrates/switchyard-py/src/lib.rscrates/switchyard-py/src/libsy_bindings.rscrates/switchyard-py/src/py_serde.rsswitchyard/libsy/__init__.pyswitchyard/libsy/algorithms.pyswitchyard_rust/libsy.pyswitchyard_rust/libsy.pyitests/test_libsy_minimal_bindings.py
|
I go this from Claude. Could you check it?
|
469a13b to
5438255
Compare
Signed-off-by: nachiketb <nachiketb@nvidia.com>
Signed-off-by: nachiketb <nachiketb@nvidia.com>
5438255 to
7df1473
Compare
Why
The typed protocol approach in #88 duplicates the Rust IR across thousands of lines of PyO3 wrappers and stubs. Python only needs to configure clients, select a Rust-owned algorithm, and run it. Maintaining a class-for-class mirror is unnecessary for that use case.
This replaces that design with a deliberately small aggregate-only API. It does not expose
Step,run_stream, protocol classes, custom Python algorithms, or optional target clients.What
switchyard.libsy.Algorithmwith onlyrun(request)LlmTarget(name, client)valuesLlmClientprotocol withasync call(request, *, target)algorithms.noop()andalgorithms.random(targets)factoriesThe complete implementation, typing surface, example, and tests add 507 lines.
How
pythonizeconverts dictionaries directly to and from the Serde-ownedswitchyard-protocoltypes. A small Rust adapter invokes the configured Python client's asynccallmethod, parses its aggregate response dictionary, and lets libsy's existingAlgorithm::rundrive the algorithm to completion.Each target requires a client because Python has no host-driven step stream with which to fulfill an unserved call.
What to review
call(request, *, target)Validation
cargo fmt --all --checkcargo clippy --workspace --all-targets -- -D warningscargo test --workspaceuv run ruff check .uv run mypy switchyard switchyard_rust/libsy.py