Skip to content

fix(stats): record noop routes in /v1/routing/stats#109

Open
elyasmnvidian wants to merge 4 commits into
mainfrom
emehtabuddin/qa-stats
Open

fix(stats): record noop routes in /v1/routing/stats#109
elyasmnvidian wants to merge 4 commits into
mainfrom
emehtabuddin/qa-stats

Conversation

@elyasmnvidian

@elyasmnvidian elyasmnvidian commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Before this change, a type: noop route never showed up in GET /v1/routing/stats. The no-op profile returned its fixed "pong" response without telling the stats accumulator which model served the request, so the response-side stats processor bucketed the tokens under <unknown> and never counted the call. total_requests stayed at 0 and there was no noop entry.

Now run_with_context sets ctx.selected_model = "noop" and calls record_success("noop") before it builds the response. The call is counted once: record_success bumps total_requests and the model's calls, and the response processor only adds tokens. So the route shows up as the noop model with its request count and token totals.

This mirrors how the latency-service backend already reports itself: set ctx.selected_model so the Rust StatsResponseProcessor attributes usage to the right model, plus record_success so the call is counted.

This is the route-bundle / route-table serving path (the same path switchyard launch builds). Serving a Python-defined profile through serve --config uses a separate adapter that does not attach a routing-stats accumulator, so that path is unaffected here.

How to try it — serve a route bundle with a noop route, send one request, then read the stats:

# noop.yaml
defaults:
  api_key: unused
  base_url: https://openrouter.ai/api/v1
  format: openai
routes:
  bench:
    type: noop
switchyard --routing-profiles noop.yaml serve --port 4000
curl -s localhost:4000/v1/chat/completions \
  -d '{"model":"bench","messages":[{"role":"user","content":"ping"}]}'
curl -s localhost:4000/v1/routing/stats

On this branch /v1/routing/stats shows total_requests: 1 and a noop model with calls: 1 and its token totals; on main it shows total_requests: 0 and an <unknown> bucket instead.

Added test_noop_call_reports_routing_stats, which builds the profile through the same with_runtime_components(...) path the route bundle uses and asserts total_requests == 1, a noop model entry with calls == 1 and token totals 1/1/2, and no <unknown> bucket.

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The no-op profile now accepts and propagates an optional StatsAccumulator, records successful noop requests, sets the selected model, and adds a test verifying routing statistics.

Changes

No-op routing statistics

Layer / File(s) Summary
Runtime statistics wiring
switchyard/lib/profiles/noop.py
NoopProfile stores an optional accumulator and passes it through runtime construction when statistics are enabled.
Request statistics recording
switchyard/lib/profiles/noop.py, tests/test_noop_llm_backend.py
No-op calls select model "noop", record successful interactions, and verify request and model counters without an "<unknown>" entry.

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

Poem

I’m a bunny with a noop reply,
Counting hops as requests fly.
“Noop” gets a tally, neat and bright,
Unknown stays out of sight.
Stats now bloom—what a delight!

🚥 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 is concise and accurately summarizes the main change: recording noop routes in routing stats.

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 (1)
tests/test_noop_llm_backend.py (1)

110-124: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Assert the noop token counters as well.

This regression only checks request and call counts. It would still pass if token statistics were dropped or recorded under another model. Add assertions for the accumulator’s prompt, completion, and total-token fields using the expected noop values.

🤖 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 `@tests/test_noop_llm_backend.py` around lines 110 - 124, Extend
test_noop_call_reports_routing_stats to assert the noop model’s prompt-token,
completion-token, and total-token counters in snap["models"]["noop"], using the
expected noop values and confirming token statistics are recorded under the noop
model.
🤖 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/profiles/noop.py`:
- Around line 223-225: Move the _stats_accumulator.record_success call in the
noop request flow to after await self.rprocess(...), ensuring request
translation, response construction, and response processing complete
successfully before recording. Keep the existing _NOOP_MODEL arguments and only
record success for fully completed calls.

---

Nitpick comments:
In `@tests/test_noop_llm_backend.py`:
- Around line 110-124: Extend test_noop_call_reports_routing_stats to assert the
noop model’s prompt-token, completion-token, and total-token counters in
snap["models"]["noop"], using the expected noop values and confirming token
statistics are recorded under the noop model.
🪄 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: 255f39dc-7318-4d8f-bf68-fb8d817bff3e

📥 Commits

Reviewing files that changed from the base of the PR and between 2fa6b87 and 2eabc4f.

📒 Files selected for processing (2)
  • switchyard/lib/profiles/noop.py
  • tests/test_noop_llm_backend.py

Comment thread switchyard/lib/profiles/noop.py Outdated
@elyasmnvidian
elyasmnvidian force-pushed the emehtabuddin/qa-stats branch from 2eabc4f to 3e68f8a Compare July 21, 2026 21:25
@elyasmnvidian

Copy link
Copy Markdown
Contributor Author

Live before/after — the noop route now records routing stats

Ran the real route-bundle serving path on both main and this branch: serve a bundle with a type: noop route, send one request, read GET /v1/routing/stats.

Bundle (bench is the noop route):

defaults: { api_key: unused, base_url: https://openrouter.ai/api/v1, format: openai }
routes:
  bench:
    type: noop

Request (identical on both): POST /v1/chat/completions {"model":"bench","messages":[{"role":"user","content":"ping"}]}200, response "model":"noop", usage 1/1/2.

Before (main) — the call is not counted and its tokens land under <unknown>:

total_requests: 0
models:
  "<unknown>": { calls: 0, request_pct: 0.0, prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }

After (this branch) — the call is counted and recorded under noop, no <unknown> bucket:

total_requests: 1
models:
  "noop": { calls: 1, request_pct: 100.0, prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 }

@elyasmnvidian
elyasmnvidian force-pushed the emehtabuddin/qa-stats branch from 85f47b3 to 6e29e16 Compare July 22, 2026 17:29
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
(cherry picked from commit 1a0c5cf)
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
Signed-off-by: Elyas Mehtabuddin <emehtabuddin@nvidia.com>
@elyasmnvidian
elyasmnvidian force-pushed the emehtabuddin/qa-stats branch from 6e29e16 to c9d9e5c Compare July 22, 2026 17:43
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.

1 participant