fix(libsy): preserve classifier system instruction - #195
Conversation
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: 📒 Files selected for processing (1)
WalkthroughThe capability judge request now stores the system prompt in ChangesCapability Judge Request
Estimated code review effort: 2 (Simple) | ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Comment |
ryan-lempka
left a comment
There was a problem hiding this comment.
This makes sense the classifier prompt should be a proper system message. This is how the classifier worked pre-libsy. Nice catch @bbednarski9!
What
Make the libsy LLM capability classifier place its governing policy in
LlmRequest.instructionsas a systemInstructionBlock. Keep only the taskconversation in
LlmRequest.messages, and extend the existing request-buildertest to lock in that separation.
This is a focused libsy correctness fix. It is independent of raw-stream
preservation PR #192 and does not change streaming types, translation APIs, or
Relay code.
Why
switchyard-protocoldeliberately separates model instructions from ordinaryconversation messages. The classifier labeled its policy
Role::System, butinserted it into
messages. On the OpenAI Chat translation path, ordinarymessages with that role are encoded as user content, so a provider received:
instead of:
That breaks the classifier router specifically because its judge call depends
on a library-authored policy prompt. The random router does not synthesize a
judge prompt and is unaffected.
The issue was reproduced through NeMo Relay's real
Algorithm::run_streamdispatcher against the unmodified Switchyard baseline: a provider-boundary
assertion expected the classifier policy to have role
systembut observeduser. Applying only this change made the same buffered and streaming processtests pass. A real Inference Hub smoke test then completed classifier and
selected-target calls for both buffered and streaming requests.
This restores the protocol and translation invariant at the source rather than
adding a Relay-specific translation workaround. It is not presented as a
general prompt-injection mitigation.
No linked issue.
How tested
uv run ruff check .cleanuv run mypy switchyardcleanuv run pytest tests/green (1,723 passed, 35 skipped)Additional Rust validation:
cargo fmt --all --checkcargo clippy --workspace --all-targets -- -D warningscargo test -p switchyard-libsy(195 unit, 3 observability, and 4 prompt tests passed)Checklist
Signed-off-by: Your Name <email>) per the DCO.Notes for reviewers
The key invariant is that classifier-owned policy belongs in
LlmRequest.instructions, while the conversation being classified remains inLlmRequest.messages. Please pay particular attention to preserving that splitas prompt-window behavior evolves.
This branch is based directly on current
mainand contains one commit changingonly
crates/libsy/src/algorithms/llm_class.rs; it is not stacked on PR #192.Summary by CodeRabbit