Skip to content

feat(libsy): stateful FallThrough routing algorithm + composable building blocks for libsy#101

Open
messiaen wants to merge 1 commit into
mainfrom
grclark/libsy-fallthrough
Open

feat(libsy): stateful FallThrough routing algorithm + composable building blocks for libsy#101
messiaen wants to merge 1 commit into
mainfrom
grclark/libsy-fallthrough

Conversation

@messiaen

@messiaen messiaen commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Introduces a session-stateful routing algorithm to libsy along with the reusable
primitives it's built from. FallThrough runs a processor chain → classifier
cascade → routed model call
, carrying State across turns so routing can depend
on accumulated session history rather than the current request alone.

What's added

  • core::State — a type-keyed bag (get/get_mut/insert/entry_or_insert_with)
    that holds per-session facts and persists across turns.
  • core::Processor + Event — an async trait that folds observed events
    (Request, Decision, ModelRequest/ModelResponse, Signal) into State.
  • core::Classifier — an async trait returning a Classification
    (Scores / Ambiguous) of Scores; argmax picks the highest confidence with
    cascade order as the tie-break (first-listed target wins).
  • algorithms::FallThrough — holds session State under a lock; each turn
    accumulates request-side facts through its processors, falls through classifiers
    until one decides, publishes the Decision, and replays it to the processors so
    stateful ones can bind it.
  • Minor: Signals relocated into protocol::envelope.

Testing

Unit tests cover each primitive in isolation (State keying, Processor event
tallying, Classifier argmax/tie-break/ambiguity) and the FallThrough cascade
end-to-end: highest-confidence selection, fall-through on abstain, first-decider-wins,
all-abstain error, per-request driver hand-off, request→decision replay ordering, and
cross-turn state persistence (routing flips once an accumulated turn counter
crosses a threshold — proving State survives between turns).

Checklist

  • One class per file; filename = snake_case of the primary class.
  • New public symbols exported from switchyard/__init__.py.__all__ if intended for downstream use.
  • Unit tests added for new components / bug fixes.
  • README / --help updated if customer-facing surface changed.
  • Commits signed off (Signed-off-by: Your Name <email>) per the DCO.

Notes for reviewers

Anything reviewers should pay extra attention to — risky paths, follow-up tickets, intentional trade-offs.

Summary by CodeRabbit

  • New Features
    • Added fall-through routing to select an LLM target using ordered classifiers and confidence scores.
    • Added processor support for request handling, decisions, model interactions, and persistent session state.
    • Exposed classifier, processor, and state APIs for extensible routing workflows.
    • Added typed state storage and default metadata construction.
  • Bug Fixes
    • Improved routing behavior for abstentions, ties, and cascading classifier decisions.

@messiaen
messiaen requested a review from a team as a code owner July 21, 2026 17:43
@messiaen messiaen self-assigned this Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Changes

Routing core

Layer / File(s) Summary
Core state and event contracts
crates/libsy/src/core/state.rs, crates/libsy/src/core/processor.rs, crates/libsy/src/core.rs
Adds typed session state, processor events and traits, associated tests, and crate-level re-exports.
Classification and scoring contract
crates/libsy/src/core/classifier.rs
Adds scored and ambiguous classifications, deterministic argmax selection, the async classifier trait, and tests.
Fall-through routing execution
crates/libsy/src/algorithms/fall_through.rs, crates/libsy/src/algorithms.rs
Adds fall-through classifier selection, processor replay, session persistence, target invocation, decision types, exports, and integration tests.

Protocol metadata default

Layer / File(s) Summary
Metadata default construction
crates/protocol/src/envelope.rs
Adds a derived Default implementation to Metadata.

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

Poem

I’m a rabbit routing through the hay,
Picking the clearest model today.
State hops forward, classifiers chime,
Processors remember turn by turn time.
With defaults tucked neatly in sight,
The fall-through path runs just right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 clearly summarizes the main change: a stateful FallThrough routing algorithm and supporting libsy building blocks.

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: 5

🧹 Nitpick comments (1)
crates/libsy/src/core/processor.rs (1)

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

BoxErr alias duplicated identically across three files. Same root cause: no single shared definition of the crate's boxed error type, so each new module redefines it.

  • crates/libsy/src/core/processor.rs#L17: keep as the canonical definition (or move to core.rs) and have the other two use it.
  • crates/libsy/src/core/classifier.rs#L17: replace this local alias with an import of the shared one.
  • crates/libsy/src/algorithms/fall_through.rs#L13: replace this local alias with an import of the shared one.
🤖 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/libsy/src/core/processor.rs` at line 17, The boxed error alias is
duplicated across three modules instead of being shared. Keep type alias BoxErr
in crates/libsy/src/core/processor.rs as the canonical definition, then remove
the local aliases and import BoxErr in crates/libsy/src/core/classifier.rs and
crates/libsy/src/algorithms/fall_through.rs; update visibility as needed so both
modules can access it.
🤖 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/libsy/src/algorithms/fall_through.rs`:
- Around line 35-44: Add a module-level `//!` documentation comment in the
`fall_through` module explaining its purpose and design, including the processor
chain, classifier cascade, routed model call, and session state lifecycle, so
the existing `module docs` references from `FallThrough` resolve correctly. Keep
the documentation focused on what the module does rather than build or
temporary-status details.
- Around line 71-126: Prevent create_run_task from holding the session state
mutex across external driver calls: keep the lock for processor/classifier state
mutation and decision replay, then release it before driver.info and
driver.call_llm_target. Preserve serialized state updates while ensuring
network-bound driver operations cannot block subsequent session turns
indefinitely.

In `@crates/libsy/src/core/classifier.rs`:
- Around line 19-37: Add concise Rust `///` documentation to the public
`Classification` enum and its `argmax` method. Document the distinction between
`Scores` and `Ambiguous`, and specify that `ignore_ambiguous` controls whether
`argmax` returns the best score or `None` for ambiguous classifications.
- Around line 41-49: Update argmax to rank confidence values without unwrapping
partial_cmp, using total_cmp (or otherwise explicitly rejecting non-finite
values) so NaN confidences cannot panic. Preserve the existing reverse iteration
and tie-breaking behavior where the earliest-listed target wins.

In `@crates/libsy/src/core/state.rs`:
- Around line 15-38: The public methods get, get_mut, insert, and
entry_or_insert_with need concise Rust documentation. Add /// comments
describing type-keyed lookup and mutable lookup, insert’s overwrite behavior,
and entry_or_insert_with’s lazy initialization and returned mutable reference,
while preserving their existing behavior.

---

Nitpick comments:
In `@crates/libsy/src/core/processor.rs`:
- Line 17: The boxed error alias is duplicated across three modules instead of
being shared. Keep type alias BoxErr in crates/libsy/src/core/processor.rs as
the canonical definition, then remove the local aliases and import BoxErr in
crates/libsy/src/core/classifier.rs and
crates/libsy/src/algorithms/fall_through.rs; update visibility as needed so both
modules can access it.
🪄 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: 1663c88a-f48e-49b2-baec-7074cd9f48fb

📥 Commits

Reviewing files that changed from the base of the PR and between 5ae2a0f and 27ca37d.

📒 Files selected for processing (7)
  • crates/libsy/src/algorithms.rs
  • crates/libsy/src/algorithms/fall_through.rs
  • crates/libsy/src/core.rs
  • crates/libsy/src/core/classifier.rs
  • crates/libsy/src/core/processor.rs
  • crates/libsy/src/core/state.rs
  • crates/protocol/src/envelope.rs

Comment thread crates/libsy/src/algorithms/fall_through.rs
Comment thread crates/libsy/src/algorithms/fall_through.rs
Comment thread crates/libsy/src/core/classifier.rs
Comment thread crates/libsy/src/core/classifier.rs Outdated
Comment thread crates/libsy/src/core/state.rs
@messiaen messiaen changed the title feat(libsy) stateful FallThrough routing algorithm + composable building blocks for libsy feat(libsy): stateful FallThrough routing algorithm + composable building blocks for libsy Jul 21, 2026
@messiaen
messiaen force-pushed the grclark/libsy-fallthrough branch from e89081e to 7dce16b Compare July 21, 2026 19:54
Signed-off-by: Greg Clark <grclark@nvidia.com>

chore(libsy): acrros turn persistent state test for fallthrough

Signed-off-by: Greg Clark <grclark@nvidia.com>

docs(libsy): add doc strings

Signed-off-by: Greg Clark <grclark@nvidia.com>

chore(libsy): review feedback

Signed-off-by: Greg Clark <grclark@nvidia.com>

fix(libsy): default response timeout 10min for fulfill_request

Signed-off-by: Greg Clark <grclark@nvidia.com>

fix(libsy): add stream started guard

Signed-off-by: Greg Clark <grclark@nvidia.com>
@messiaen
messiaen force-pushed the grclark/libsy-fallthrough branch from 4ce6031 to 6bd0402 Compare July 21, 2026 21:23
@messiaen messiaen assigned ayushag-nv and unassigned ayushag-nv Jul 21, 2026
@messiaen
messiaen requested a review from ayushag-nv July 21, 2026 22:30
@messiaen
messiaen force-pushed the grclark/libsy-fallthrough branch from 54d6700 to 6bd0402 Compare July 22, 2026 00:10
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