Skip to content

refactor(core): replace Rust compatibility APIs with Python - #175

Merged
ayushag-nv merged 2 commits into
mainfrom
nachiketb/remove-switchyard-core
Jul 29, 2026
Merged

refactor(core): replace Rust compatibility APIs with Python#175
ayushag-nv merged 2 commits into
mainfrom
nachiketb/remove-switchyard-core

Conversation

@nachiketb-nvidia

@nachiketb-nvidia nachiketb-nvidia commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What

  • Remove the unused switchyard-core crate.
  • Replace the public PyO3 core classes with Python-owned request, response, stream, context, metadata, backend, session-key, and session-cache APIs.
  • Keep only private Rust interop required by native components.

Why

The compatibility chain no longer needs a separate Rust core crate or a Rust-owned Python surface. Python callers should own Python control-plane values, while native processors should receive explicit adapters instead of defining the public API.

How

  • Move the remaining Rust contracts into private switchyard-components modules.
  • Implement the Python enums, value objects, context wrapper, and nominal LLMBackend role in switchyard_rust.core.
  • Register native backend classes as virtual LLMBackend implementations.
  • Convert Python request and response fields directly at native processor boundaries; no native request or response envelope remains.
  • Keep private native adapters only for typed context state, backend extraction, and stream lifetime ownership.
  • Move canonical session-affinity keying and cache behavior to Python.
  • Remove the native metadata mapping; arbitrary request metadata is now a normal Python dictionary.

Scope

This removes switchyard-core, the public core_bindings module, and the redundant _NativeChatRequest and _NativeChatResponse containers. It does not remove public Python exports or compatibility-chain features. Private interop remains only where native typed state or resource ownership requires it.

What to review

  • Direct Python-to-Rust request and response conversion.
  • Public request, response, context, and metadata behavior and JSON ownership.
  • Stream callback and close behavior across Python to Rust to Python handoff.
  • Native backend isinstance and composition behavior.
  • Session-affinity key compatibility and cache behavior.
  • The private interop boundary: only context, backend, and stream adapters remain native.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo test --workspace
  • uv run maturin develop
  • uv run ruff check .
  • uv run mypy switchyard
  • uv run pytest tests/ -q (1723 passed, 35 skipped)

@nachiketb-nvidia
nachiketb-nvidia requested a review from a team as a code owner July 29, 2026 00:53
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

The workspace removes switchyard-core as a workspace dependency, exposes compatibility contracts through switchyard-components, updates Rust and Python bindings, and replaces native session caching and key generation with Python implementations and tests.

Components Migration

Layer / File(s) Summary
Workspace and compatibility contracts
Cargo.toml, crates/switchyard-components/Cargo.toml, crates/switchyard-components/src/contracts/*, crates/switchyard-components/src/lib.rs
Workspace wiring and public compatibility contracts move into switchyard-components, with selected identifier types retained and re-exported.
Component implementation import wiring
crates/switchyard-components/src/backends/*, src/intake/*, src/request_processors/*, src/response_processors/*, src/stats/*, src/dimension_collector/*
Shared types are imported from the local components crate without changing processing logic.
Component test API migration
crates/switchyard-components/tests/*
Integration tests and support helpers use switchyard-components APIs, with identifier assertions updated.
Python binding migration
crates/switchyard-py/Cargo.toml, crates/switchyard-py/src/*
Python bindings switch shared types and errors to switchyard-components and register subagent bindings instead of session bindings.

Python Session Primitives

Layer / File(s) Summary
Pure-Python session cache
switchyard/lib/session_cache.py, switchyard/lib/profiles/chain.py, switchyard/lib/session_affinity.py
A generic bounded LRU SessionCache replaces the native cache, and callers provide explicit value types.
Pure-Python session-key generation
switchyard/lib/session_key.py
Conversation content is normalized and hashed in Python, including depth handling and tool-call data.
Native surface cleanup and primitive tests
switchyard_rust/core.py, tests/test_session_primitives.py
Native exports drop the moved primitives, with tests covering cache and session-key behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Poem

I’m a bunny with contracts tucked neat,
Components hop on lighter feet.
Python keys bloom, caches gently sway,
Rust session bindings burrow away.
Tests nibble bugs till they’re gone—
Then I thump at the passing dawn!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: moving compatibility APIs from Rust to Python and refactoring the core layer.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
switchyard/lib/session_cache.py (1)

18-21: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the ValueError in __init__.

Per coding guidelines, public entry points should document raised errors; __init__ raises ValueError for negative max_sessions but has no docstring.

📝 Proposed docstring
     def __init__(self, max_sessions: int) -> None:
+        """Create a cache bounded to ``max_sessions`` entries.
+
+        Raises:
+            ValueError: If ``max_sessions`` is negative.
+        """
         if max_sessions < 0:
             raise ValueError("max_sessions must be non-negative")
🤖 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 `@switchyard/lib/session_cache.py` around lines 18 - 21, Add a docstring to the
public __init__ method documenting that it raises ValueError when max_sessions
is negative, while preserving the existing validation and initialization
behavior.

Source: Coding guidelines

switchyard/lib/session_key.py (1)

21-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Docstring omits the ValueError and None-return contract.

depth < 0 raises ValueError, and the function returns None when depth > 0 and the prefix is incomplete — neither is documented.

📝 Proposed docstring
 def session_key_from_body(body: Any, depth: int = 0) -> str | None:
-    """Hash stable conversation anchors and an optional early-response prefix."""
+    """Hash stable conversation anchors and an optional early-response prefix.
+
+    Raises:
+        ValueError: If ``depth`` is negative.
+
+    Returns ``None`` when ``depth > 0`` and the conversation does not yet
+    contain ``depth`` complete messages after the anchoring user turn.
+    """
🤖 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 `@switchyard/lib/session_key.py` around lines 21 - 24, Update the docstring for
session_key_from_body to document that negative depth raises ValueError and that
the function returns None when depth is greater than zero but the response
prefix is incomplete, while preserving the existing description.

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 `@switchyard/lib/session_key.py`:
- Around line 81-97: Update the tool-call argument handling in the visible
tool-call serialization logic so non-string values use _json_text(raw_arguments)
instead of being replaced with an empty string. Apply this consistently in both
the nested tool_calls/function block and the top-level type == "function_call"
block, while preserving string arguments unchanged.

---

Nitpick comments:
In `@switchyard/lib/session_cache.py`:
- Around line 18-21: Add a docstring to the public __init__ method documenting
that it raises ValueError when max_sessions is negative, while preserving the
existing validation and initialization behavior.

In `@switchyard/lib/session_key.py`:
- Around line 21-24: Update the docstring for session_key_from_body to document
that negative depth raises ValueError and that the function returns None when
depth is greater than zero but the response prefix is incomplete, while
preserving the existing description.
🪄 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: 3916dd33-acd7-4c86-a4c1-04b82a24b986

📥 Commits

Reviewing files that changed from the base of the PR and between 61f41ff and 6514d24.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !Cargo.lock
📒 Files selected for processing (67)
  • Cargo.toml
  • crates/switchyard-components/Cargo.toml
  • crates/switchyard-components/src/backends/anthropic.rs
  • crates/switchyard-components/src/backends/common.rs
  • crates/switchyard-components/src/backends/multi.rs
  • crates/switchyard-components/src/backends/openai.rs
  • crates/switchyard-components/src/backends/selection.rs
  • crates/switchyard-components/src/backends/stats.rs
  • crates/switchyard-components/src/contracts/backend.rs
  • crates/switchyard-components/src/contracts/context.rs
  • crates/switchyard-components/src/contracts/error.rs
  • crates/switchyard-components/src/contracts/ids.rs
  • crates/switchyard-components/src/contracts/mod.rs
  • crates/switchyard-components/src/contracts/roles.rs
  • crates/switchyard-components/src/contracts/types.rs
  • crates/switchyard-components/src/dimension_collector/response/checks.rs
  • crates/switchyard-components/src/dimension_collector/response/mod.rs
  • crates/switchyard-components/src/dimension_collector/tool_signals.rs
  • crates/switchyard-components/src/intake/client.rs
  • crates/switchyard-components/src/intake/context.rs
  • crates/switchyard-components/src/intake/payload.rs
  • crates/switchyard-components/src/lib.rs
  • crates/switchyard-components/src/request_processors/dimension_collector.rs
  • crates/switchyard-components/src/request_processors/intake.rs
  • crates/switchyard-components/src/request_processors/random_routing.rs
  • crates/switchyard-components/src/request_processors/stats.rs
  • crates/switchyard-components/src/response_processors/intake.rs
  • crates/switchyard-components/src/response_processors/response_signals.rs
  • crates/switchyard-components/src/response_processors/stats.rs
  • crates/switchyard-components/src/stats/accumulator.rs
  • crates/switchyard-components/src/stats/context.rs
  • crates/switchyard-components/src/stats/usage.rs
  • crates/switchyard-components/tests/adversarial_multi_llm_backend.rs
  • crates/switchyard-components/tests/adversarial_native_backends.rs
  • crates/switchyard-components/tests/adversarial_random_routing.rs
  • crates/switchyard-components/tests/contracts.rs
  • crates/switchyard-components/tests/flat_target_live.rs
  • crates/switchyard-components/tests/intake_http_sink.rs
  • crates/switchyard-components/tests/intake_payload.rs
  • crates/switchyard-components/tests/intake_request_processor.rs
  • crates/switchyard-components/tests/intake_response_processor.rs
  • crates/switchyard-components/tests/stats_accumulator.rs
  • crates/switchyard-components/tests/stats_processors.rs
  • crates/switchyard-components/tests/support/config.rs
  • crates/switchyard-components/tests/support/intake.rs
  • crates/switchyard-components/tests/support/mod.rs
  • crates/switchyard-core/Cargo.toml
  • crates/switchyard-core/src/lib.rs
  • crates/switchyard-core/src/session.rs
  • crates/switchyard-py/Cargo.toml
  • crates/switchyard-py/src/component_bindings/backends.rs
  • crates/switchyard-py/src/component_bindings/config.rs
  • crates/switchyard-py/src/component_bindings/dimension_collector.rs
  • crates/switchyard-py/src/core_bindings.rs
  • crates/switchyard-py/src/core_bindings/context.rs
  • crates/switchyard-py/src/core_bindings/request.rs
  • crates/switchyard-py/src/core_bindings/response.rs
  • crates/switchyard-py/src/core_bindings/roles.rs
  • crates/switchyard-py/src/core_bindings/session.rs
  • crates/switchyard-py/src/errors.rs
  • switchyard/lib/affinity_pin_store.py
  • switchyard/lib/profiles/chain.py
  • switchyard/lib/session_affinity.py
  • switchyard/lib/session_cache.py
  • switchyard/lib/session_key.py
  • switchyard_rust/core.py
  • tests/test_session_primitives.py
💤 Files with no reviewable changes (5)
  • crates/switchyard-core/Cargo.toml
  • crates/switchyard-core/src/session.rs
  • crates/switchyard-py/src/core_bindings/session.rs
  • crates/switchyard-core/src/lib.rs
  • switchyard_rust/core.py

Comment thread switchyard/lib/session_key.py
@nachiketb-nvidia
nachiketb-nvidia force-pushed the nachiketb/remove-switchyard-core branch from 6514d24 to bd31657 Compare July 29, 2026 01:38
@nachiketb-nvidia nachiketb-nvidia changed the title refactor(core): remove switchyard-core crate refactor(core): replace Rust compatibility APIs with Python Jul 29, 2026
Signed-off-by: nachiketb <nachiketb@nvidia.com>
@nachiketb-nvidia
nachiketb-nvidia force-pushed the nachiketb/remove-switchyard-core branch from bd31657 to 2f1b2c8 Compare July 29, 2026 06:31
Signed-off-by: nachiketb <nachiketb@nvidia.com>

@ayushag-nv ayushag-nv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love it

@ayushag-nv
ayushag-nv merged commit e4632e3 into main Jul 29, 2026
17 checks passed
@ayushag-nv
ayushag-nv deleted the nachiketb/remove-switchyard-core branch July 29, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants