Skip to content

fix(server): omit absent request-log ids instead of logging them empty (#301) - #2

Open
chethanuk wants to merge 1 commit into
mainfrom
fix/request-log-absent-vs-empty-ids-301
Open

chethanuk wants to merge 1 commit into
mainfrom
fix/request-log-absent-vs-empty-ids-301

Conversation

@chethanuk

@chethanuk chethanuk commented Sep 5, 2026 •

Copy link
Copy Markdown
Owner

Closes the last open part of NVIDIA-NeMo/Switchyard issue 301.

Problem

The terminal request log renders an absent session id and an empty one the same way, session_id= correlation_id=. An operator cannot tell whether the client sent no session or a blank one.

Change

RequestLogContext::emit and emit_cancelled passed session_id and correlation_id through .unwrap_or(""). Dropping it lets tracing skip the field when the id is None; Some("x") still logs session_id=x. requested_model, selected_model and error keep unwrap_or(""), since emit_cancelled hardcodes an empty selected_model and absent and empty mean the same there.

Some("") cannot come from HTTP today (resolve_path returns None for empty shapes), so the visible change is that an absent session stops printing session_id=. The empty row in the test guards a shape the type allows.

CapturedEvents in the test module now yields a named CapturedEvent { level, message } instead of a (Level, String) tuple, as requested in review.

Testing

request_log_distinguishes_absent_ids_from_empty_ones covers the answered and cancelled paths for absent, empty and non-empty ids. With the fix reverted it fails with session_id None: ... session_id="" ... left: Some("\"\"") right: None.

cargo fmt --all --check                                          # clean
cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
cargo test -p switchyard-server                                  # all pass

cargo clippy --workspace also flags crates/prefill-router/src/transformers.rs, which this change does not touch.

@codeant-ai

codeant-ai Bot commented Sep 5, 2026 •

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed 1526379 Oct 02, 2026 · 09:02 09:02
✅ Incremental review completed 07a3daf Oct 01, 2026 · 20:32 20:33
✅ Incremental review completed c83fb86 Sep 30, 2026 · 15:24 15:24
✅ Incremental review completed 02dfaf0 Sep 30, 2026 · 10:00 10:00
✅ Incremental review completed f27a05d Sep 05, 2026 · 04:47 04:48

@codeant-ai

codeant-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown

Thanks for using CodeAnt! 🎉

We're free for open-source projects. if you're enjoying it, help us grow by sharing.

Share on X ·
Reddit ·
LinkedIn

@coderabbitai

coderabbitai Bot commented Sep 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 06f96498-682e-4f71-9421-91b0e502cc96

📥 Commits

Reviewing files that changed from the base of the PR and between 9a743e8 and f27a05d.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • crates/switchyard-server/src/lib.rs

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


Walkthrough

Terminal request events now omit absent session_id and correlation_id fields while preserving explicitly empty values. The capture harness records event fields, and tests cover answered and cancelled requests with absent, empty, and non-empty identifiers.

Changes

Request log identifier handling

Layer / File(s) Summary
Optional event fields
crates/switchyard-server/src/lib.rs, CHANGELOG.md
Answered and cancelled request events now record absent identifiers as omitted fields. The changelog documents the fix.
Field capture and validation
crates/switchyard-server/src/lib.rs
The test harness captures event fields in maps. A new test checks absent, empty, and non-empty identifiers for answered and cancelled events.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to f27a0

Terminal request logs now omit absent session and correlation IDs while retaining explicitly empty and populated IDs. The behavior is covered for answered and cancelled requests, with no remaining merge-blocking risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 1 files. (1 skipped: … 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 clearly and concisely describes the main change: absent request-log IDs are omitted instead of logged as empty values.
Full details: Docstring Coverage

Explanation

Docstring coverage is 36.36% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 1 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

I’m a rabbit, and fields now know when to hide,
Empty strings still hop along inside.
Answered logs and cancelled trails
Carry clear keys, or leave no trails.
My tiny test bounds through the night,
Keeping each identifier right.

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

@codeant-ai codeant-ai Bot added the size:M This PR changes 30-99 lines, ignoring generated files label Sep 5, 2026
@codeant-ai

codeant-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown

User description

Closes the last open part of NVIDIA-NeMo#301. Parts 1 and 2 landed in NVIDIA-NeMo#308.

Problem

The terminal request log cannot tell an absent session id from an empty one. Both render the
same way:

session_id= correlation_id=

An operator reading that line cannot say whether the client sent no session at all or sent a
blank one — which is exactly the distinction NVIDIA-NeMo#308's affinity warning asks them to act on.

Root cause

RequestLogContext::emit and emit_cancelled render their optional ids through
.unwrap_or(""):

session_id = self.session_id.as_deref().unwrap_or(""),
correlation_id = self.correlation_id.as_deref().unwrap_or(""),

Option<String> carries the distinction; unwrap_or("") throws it away at the point of
logging. Both emit paths repeat the same line, so fixing only one leaves the cancelled path
ambiguous.

The fix

Drop .unwrap_or("") at both sites. tracing-core's impl<T: Value> Value for Option<T>
(pinned at 0.1.36 in Cargo.lock) is a no-op on None, so an absent id now omits the field
entirely, while Some("x") still records session_id=x byte-identically to before. No format
string, no sentinel, no new dependency.

requested_model, selected_model and error keep unwrap_or("") deliberately:
emit_cancelled hardcodes selected_model = "", so for those three "absent" and "empty" mean
the same thing by design, and splitting them would divide the two emit paths for no gain.

Scope — what this does and does not claim

The only non-test producer of session_id is resolve_path, which returns None for every
empty shape. So Some("") is unreachable over HTTP today: the user-visible change is that an
absent session stops printing session_id=. The empty-string row in the test is a regression
guard on a shape the type permits, not a bug being fixed. This is a log-correctness fix plus
that guard.

Nothing in the tree documents or parses these lines, the sink is fmt rather than .json(),
and OTLP treats an unrecorded field as unset — which is what makes omission safe rather than
breaking. Open question for maintainers: whether an out-of-tree log consumer relies on the field
always being present. If so, the fallback is a sentinel (unwrap_or("<absent>")), which has no
precedent in this codebase.

Test evidence

The test drives both terminal paths (answered and cancelled) over all three id shapes, and fails
without the fix with the issue's exact symptom:

$ cargo test -p switchyard-server request_log
test tests::request_log_distinguishes_absent_ids_from_empty_ones ... FAILED

thread '...' panicked at crates/switchyard-server/src/lib.rs:2022:21:
assertion `left == right` failed: session_id None
  left: Some("")
 right: None

test result: FAILED. 3 passed; 1 failed; 0 ignored; 16 filtered out

With the fix:

$ cargo test -p switchyard-server --lib request_log
test result: ok. 4 passed; 0 failed; 0 ignored; 16 filtered out

Asserting on absence needs the test subscriber to capture fields, not just the message, so
CapturedEvents now records every field into a BTreeMap via a Visit impl — an absent field
is a missing key rather than an empty value. The two existing callers read .0/.1 and are
unchanged.

Full gate, per AGENTS.md:256:

$ cargo fmt --all --check                                     # clean
$ cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
$ cargo test --workspace                                      # 586 passed, 0 failed, 1 ignored

cargo clippy --workspace fails on crates/prefill-router/src/transformers.rs:179 and :213
(chunks_exact_to_as_chunks). That crate is untouched here — last changed by NVIDIA-NeMo#539 on
origin/main — and cargo clippy -p prefill-router reproduces it on its own, so it is
pre-existing and left alone.

Upstream issue: NVIDIA-NeMo#301


CodeAnt-AI Description

Distinguish absent request IDs from empty request IDs in terminal logs

What Changed

  • Request logs now omit session_id and correlation_id when a request does not provide them, instead of displaying them as empty fields.
  • Explicitly empty IDs remain recorded as empty, while provided IDs continue to appear unchanged.
  • The behavior is covered for both completed and client-cancelled requests.

Impact

✅ Clearer request-log diagnostics
✅ Distinguishable missing and blank request IDs
✅ Consistent completed and cancelled request logs

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@chethanuk
chethanuk force-pushed the fix/request-log-absent-vs-empty-ids-301 branch from eb857e6 to f27a05d Compare September 5, 2026 04:47
@codeant-ai

codeant-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown

User description

Closes the last open part of NVIDIA-NeMo#301. Parts 1 and 2 landed in NVIDIA-NeMo#308.

Problem

The terminal request log cannot tell an absent session id from an empty one. Both render the
same way:

session_id= correlation_id=

An operator reading that line cannot say whether the client sent no session at all or sent a
blank one — which is exactly the distinction NVIDIA-NeMo#308's affinity warning asks them to act on.

Root cause

RequestLogContext::emit and emit_cancelled render their optional ids through
.unwrap_or(""):

session_id = self.session_id.as_deref().unwrap_or(""),
correlation_id = self.correlation_id.as_deref().unwrap_or(""),

Option<String> carries the distinction; unwrap_or("") throws it away at the point of
logging. Both emit paths repeat the same line, so fixing only one leaves the cancelled path
ambiguous.

The fix

Drop .unwrap_or("") at both sites. tracing-core's impl<T: Value> Value for Option<T>
(pinned at 0.1.36 in Cargo.lock) is a no-op on None, so an absent id now omits the field
entirely, while Some("x") still records session_id=x byte-identically to before. No format
string, no sentinel, no new dependency.

requested_model, selected_model and error keep unwrap_or("") deliberately:
emit_cancelled hardcodes selected_model = "", so for those three "absent" and "empty" mean
the same thing by design, and splitting them would divide the two emit paths for no gain.

Scope — what this does and does not claim

The only non-test producer of session_id is resolve_path, which returns None for every
empty shape. So Some("") is unreachable over HTTP today: the user-visible change is that an
absent session stops printing session_id=. The empty-string row in the test is a regression
guard on a shape the type permits, not a bug being fixed. This is a log-correctness fix plus
that guard.

Nothing in the tree documents or parses these lines, the sink is fmt rather than .json(),
and OTLP treats an unrecorded field as unset — which is what makes omission safe rather than
breaking. Open question for maintainers: whether an out-of-tree log consumer relies on the field
always being present. If so, the fallback is a sentinel (unwrap_or("<absent>")), which has no
precedent in this codebase.

Test evidence

The test drives both terminal paths (answered and cancelled) over all three id shapes, and fails
without the fix with the issue's exact symptom:

$ cargo test -p switchyard-server request_log
test tests::request_log_distinguishes_absent_ids_from_empty_ones ... FAILED

thread '...' panicked at crates/switchyard-server/src/lib.rs:2022:21:
assertion `left == right` failed: session_id None
  left: Some("")
 right: None

test result: FAILED. 3 passed; 1 failed; 0 ignored; 16 filtered out

With the fix:

$ cargo test -p switchyard-server --lib request_log
test result: ok. 4 passed; 0 failed; 0 ignored; 16 filtered out

Asserting on absence needs the test subscriber to capture fields, not just the message, so
CapturedEvents now records every field into a BTreeMap via a Visit impl — an absent field
is a missing key rather than an empty value. The two existing callers read .0/.1 and are
unchanged.

Full gate, per AGENTS.md:256:

$ cargo fmt --all --check                                     # clean
$ cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
$ cargo test --workspace                                      # 586 passed, 0 failed, 1 ignored

cargo clippy --workspace fails on crates/prefill-router/src/transformers.rs:179 and :213
(chunks_exact_to_as_chunks). That crate is untouched here — last changed by NVIDIA-NeMo#539 on
origin/main — and cargo clippy -p prefill-router reproduces it on its own, so it is
pre-existing and left alone.

Upstream issue: NVIDIA-NeMo#301


CodeAnt-AI Description

Distinguish absent request identifiers in terminal logs

What Changed

  • Request logs now omit session_id and correlation_id when the request did not provide them, instead of showing them as empty fields
  • Explicitly blank identifiers remain visible as empty values, preserving the difference between absent and blank IDs for completed and cancelled requests
  • Added coverage for absent, blank, and populated identifiers in both request outcomes

Impact

✅ Clearer request troubleshooting
✅ Distinguishable missing and blank session IDs
✅ Consistent logs for cancelled requests

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@chethanuk

Copy link
Copy Markdown
Owner Author

Status: skipped. Upstream already has this change open as NVIDIA-NeMo#633, which uses this same head branch (fix/request-log-absent-vs-empty-ids-301, commit f27a05d). Issue NVIDIA-NeMo#301 is still open. Work continues on the upstream PR, so this fork PR gets no code changes, rebase or push.

@codeant-ai codeant-ai Bot added size:XXL This PR changes 1000+ lines, ignoring generated files and removed size:M This PR changes 30-99 lines, ignoring generated files labels Sep 30, 2026
@codeant-ai

codeant-ai Bot commented Sep 30, 2026

Copy link
Copy Markdown

User description

Status: skipped. Upstream already has this change open as NVIDIA-NeMo#633, which uses this same head branch (fix/request-log-absent-vs-empty-ids-301, commit f27a05d). Issue NVIDIA-NeMo#301 is still open. Work continues on the upstream PR, so this fork PR gets no code changes, rebase or push.


Closes the last open part of the upstream request. Parts 1 and 2 landed earlier.

Problem

The terminal request log cannot tell an absent session id from an empty one. Both render the
same way:

session_id= correlation_id=

An operator reading that line cannot say whether the client sent no session at all or sent a
blank one — which is exactly the distinction NVIDIA-NeMo#308's affinity warning asks them to act on.

Root cause

RequestLogContext::emit and emit_cancelled render their optional ids through
.unwrap_or(""):

session_id = self.session_id.as_deref().unwrap_or(""),
correlation_id = self.correlation_id.as_deref().unwrap_or(""),

Option<String> carries the distinction; unwrap_or("") throws it away at the point of
logging. Both emit paths repeat the same line, so fixing only one leaves the cancelled path
ambiguous.

The fix

Drop .unwrap_or("") at both sites. tracing-core's impl<T: Value> Value for Option<T>
(pinned at 0.1.36 in Cargo.lock) is a no-op on None, so an absent id now omits the field
entirely, while Some("x") still records session_id=x byte-identically to before. No format
string, no sentinel, no new dependency.

requested_model, selected_model and error keep unwrap_or("") deliberately:
emit_cancelled hardcodes selected_model = "", so for those three "absent" and "empty" mean
the same thing by design, and splitting them would divide the two emit paths for no gain.

Scope — what this does and does not claim

The only non-test producer of session_id is resolve_path, which returns None for every
empty shape. So Some("") is unreachable over HTTP today: the user-visible change is that an
absent session stops printing session_id=. The empty-string row in the test is a regression
guard on a shape the type permits, not a bug being fixed. This is a log-correctness fix plus
that guard.

Nothing in the tree documents or parses these lines, the sink is fmt rather than .json(),
and OTLP treats an unrecorded field as unset — which is what makes omission safe rather than
breaking. Open question for maintainers: whether an out-of-tree log consumer relies on the field
always being present. If so, the fallback is a sentinel (unwrap_or("<absent>")), which has no
precedent in this codebase.

Test evidence

The test drives both terminal paths (answered and cancelled) over all three id shapes, and fails
without the fix with the issue's exact symptom:

$ cargo test -p switchyard-server request_log
test tests::request_log_distinguishes_absent_ids_from_empty_ones ... FAILED

thread '...' panicked at crates/switchyard-server/src/lib.rs:2022:21:
assertion `left == right` failed: session_id None
  left: Some("")
 right: None

test result: FAILED. 3 passed; 1 failed; 0 ignored; 16 filtered out

With the fix:

$ cargo test -p switchyard-server --lib request_log
test result: ok. 4 passed; 0 failed; 0 ignored; 16 filtered out

Asserting on absence needs the test subscriber to capture fields, not just the message, so
CapturedEvents now records every field into a BTreeMap via a Visit impl — an absent field
is a missing key rather than an empty value. The two existing callers read .0/.1 and are
unchanged.

Full gate, per AGENTS.md:256:

$ cargo fmt --all --check                                     # clean
$ cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
$ cargo test --workspace                                      # 586 passed, 0 failed, 1 ignored

cargo clippy --workspace fails on crates/prefill-router/src/transformers.rs:179 and :213
(chunks_exact_to_as_chunks). That crate is untouched here — last changed by NVIDIA-NeMo#539 on
origin/main — and cargo clippy -p prefill-router reproduces it on its own, so it is
pre-existing and left alone.


CodeAnt-AI Description

Allow escalated sessions to return to the efficient model

What Changed

  • Escalation routes can now release a session back to the efficient tier after the strong tier resolves the underlying problem, with configurable confirmation counts, strong-tier limits, and cooldown turns.
  • Strong and efficient evaluations use phase-specific guidance, while existing configurations retain permanent escalation behavior when de-escalation is not enabled.
  • Python and TOML users can configure de-escalation, with validation for invalid thresholds and a warning when stateful routing has no session ID.
  • Streaming Responses preserve upstream response and reasoning IDs, including summaries that arrive before their provider ID.
  • Stream and buffered responses now accept an explicit error: null field without treating it as a failure, and request logs omit absent session or correlation IDs while preserving empty values.
  • Added configuration guidance and recipes for routing Codex and Claude Code through a single provider login.

Impact

✅ Sessions can return to efficient models after recovery
✅ Fewer unnecessary strong-tier calls
✅ Preserved conversation continuity for streamed responses

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@chethanuk
chethanuk force-pushed the fix/request-log-absent-vs-empty-ids-301 branch from 02dfaf0 to c83fb86 Compare September 30, 2026 15:24
@codeant-ai

codeant-ai Bot commented Sep 30, 2026

Copy link
Copy Markdown

User description

Closes the last open part of NVIDIA-NeMo/Switchyard issue 301.

Problem

The terminal request log renders an absent session id and an empty one the same way, session_id= correlation_id=. An operator cannot tell whether the client sent no session or a blank one.

Change

RequestLogContext::emit and emit_cancelled passed session_id and correlation_id through .unwrap_or(""). Dropping it lets tracing skip the field when the id is None; Some("x") still logs session_id=x. requested_model, selected_model and error keep unwrap_or(""), since emit_cancelled hardcodes an empty selected_model and absent and empty mean the same there.

Some("") cannot come from HTTP today (resolve_path returns None for empty shapes), so the visible change is that an absent session stops printing session_id=. The empty row in the test guards a shape the type allows.

CapturedEvents in the test module now yields a named CapturedEvent { level, message } instead of a (Level, String) tuple, as requested in review.

Testing

request_log_distinguishes_absent_ids_from_empty_ones covers the answered and cancelled paths for absent, empty and non-empty ids. With the fix reverted it fails with session_id None: ... session_id="" ... left: Some("\"\"") right: None.

cargo fmt --all --check                                          # clean
cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
cargo test -p switchyard-server                                  # all pass

cargo clippy --workspace also flags crates/prefill-router/src/transformers.rs, which this change does not touch.


CodeAnt-AI Description

Add reversible escalation routing and preserve streamed response identity

What Changed

  • Escalated sessions can optionally return to the efficient model after a configurable number of strong-tier turns and consecutive recovery verdicts.
  • Optional hard limits and cooldown periods prevent sessions from staying on the strong model indefinitely or switching tiers repeatedly.
  • Python and TOML users can configure de-escalation, with validation for invalid settings and a warning when stateful routing has no session ID.
  • Streamed Responses now keep the upstream response ID for conversation continuation and hold reasoning summaries until the provider ID is known, preserving encrypted reasoning payloads and output order.
  • Request logs omit absent session and correlation IDs instead of rendering them as empty fields; nullable error fields are accepted in soak-test responses.
  • Added configuration guidance for reversible routing and single-provider Codex and Claude Code setups.

Impact

✅ Sessions can return to efficient models after recovery
✅ Continued conversations retain streamed response history
✅ Reasoning payloads remain replayable when IDs arrive late

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

@chethanuk
chethanuk force-pushed the fix/request-log-absent-vs-empty-ids-301 branch from c83fb86 to 07a3daf Compare October 1, 2026 20:32
@codeant-ai

codeant-ai Bot commented Oct 1, 2026

Copy link
Copy Markdown

User description

Closes the last open part of NVIDIA-NeMo/Switchyard issue 301.

Problem

The terminal request log renders an absent session id and an empty one the same way, session_id= correlation_id=. An operator cannot tell whether the client sent no session or a blank one.

Change

RequestLogContext::emit and emit_cancelled passed session_id and correlation_id through .unwrap_or(""). Dropping it lets tracing skip the field when the id is None; Some("x") still logs session_id=x. requested_model, selected_model and error keep unwrap_or(""), since emit_cancelled hardcodes an empty selected_model and absent and empty mean the same there.

Some("") cannot come from HTTP today (resolve_path returns None for empty shapes), so the visible change is that an absent session stops printing session_id=. The empty row in the test guards a shape the type allows.

CapturedEvents in the test module now yields a named CapturedEvent { level, message } instead of a (Level, String) tuple, as requested in review.

Testing

request_log_distinguishes_absent_ids_from_empty_ones covers the answered and cancelled paths for absent, empty and non-empty ids. With the fix reverted it fails with session_id None: ... session_id="" ... left: Some("\"\"") right: None.

cargo fmt --all --check                                          # clean
cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
cargo test -p switchyard-server                                  # all pass

cargo clippy --workspace also flags crates/prefill-router/src/transformers.rs, which this change does not touch.


CodeAnt-AI Description

Make escalation decisions more reliable and add a supported Linux Codex setup

What Changed

  • Escalation now requires fresh evidence from the same failure category across turns, preventing duplicate command representations, stale findings, or category changes from triggering a premature switch
  • Unavailable judges preserve an in-progress confirmation streak, while declined or stale verdicts reset it; parsed decisions now record clear continue or pending outcomes
  • Upstream advisor failure bodies are redacted before reaching logs and audit records
  • Anthropic request reconstruction preserves caller-supplied thinking settings instead of replacing them with adaptive thinking when effort is also set
  • Added typed, provider-neutral decision request and response data
  • Added Linux install, dry-run, and uninstall commands for a systemd user service and Codex sy profile, with validation, backups, and preservation of user configuration
  • Request logs now omit absent session and correlation IDs while retaining explicitly empty values

Impact

✅ Fewer premature model escalations
✅ No upstream prompt leakage in advisor logs
✅ Preserved Anthropic thinking modes
✅ One-command Linux Codex setup

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Signed-off-by: ChethanUK <chethanuk@outlook.com>
@chethanuk
chethanuk force-pushed the fix/request-log-absent-vs-empty-ids-301 branch from 07a3daf to 1526379 Compare October 2, 2026 09:02
@codeant-ai codeant-ai Bot added size:M This PR changes 30-99 lines, ignoring generated files and removed size:XXL This PR changes 1000+ lines, ignoring generated files labels Oct 2, 2026
@codeant-ai

codeant-ai Bot commented Oct 2, 2026

Copy link
Copy Markdown

User description

Closes the last open part of NVIDIA-NeMo/Switchyard issue 301.

Problem

The terminal request log renders an absent session id and an empty one the same way, session_id= correlation_id=. An operator cannot tell whether the client sent no session or a blank one.

Change

RequestLogContext::emit and emit_cancelled passed session_id and correlation_id through .unwrap_or(""). Dropping it lets tracing skip the field when the id is None; Some("x") still logs session_id=x. requested_model, selected_model and error keep unwrap_or(""), since emit_cancelled hardcodes an empty selected_model and absent and empty mean the same there.

Some("") cannot come from HTTP today (resolve_path returns None for empty shapes), so the visible change is that an absent session stops printing session_id=. The empty row in the test guards a shape the type allows.

CapturedEvents in the test module now yields a named CapturedEvent { level, message } instead of a (Level, String) tuple, as requested in review.

Testing

request_log_distinguishes_absent_ids_from_empty_ones covers the answered and cancelled paths for absent, empty and non-empty ids. With the fix reverted it fails with session_id None: ... session_id="" ... left: Some("\"\"") right: None.

cargo fmt --all --check                                          # clean
cargo clippy -p switchyard-server --all-targets -- -D warnings   # clean
cargo test -p switchyard-server                                  # all pass

cargo clippy --workspace also flags crates/prefill-router/src/transformers.rs, which this change does not touch.


CodeAnt-AI Description

Distinguish absent request IDs from empty request IDs in logs

What Changed

  • Request logs now omit session_id and correlation_id when the client does not provide them
  • Explicitly empty or non-empty IDs continue to appear with their supplied values for completed and cancelled requests
  • Added coverage to verify the distinction across both request outcomes

Impact

✅ Clearer request identity diagnostics
✅ Easier troubleshooting of missing client IDs
✅ Consistent logs for completed and cancelled requests

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant