Skip to content

feat(analytics,proxy): routing headers visualization and routing mode query param - #503

Open
yanaSelin wants to merge 6 commits into
mainfrom
EPMCDME-14083
Open

feat(analytics,proxy): routing headers visualization and routing mode query param#503
yanaSelin wants to merge 6 commits into
mainfrom
EPMCDME-14083

Conversation

@yanaSelin

Copy link
Copy Markdown
Collaborator

Summary

Extract Switchyard/LiteLLM routing metadata from proxy response headers stored in Claude native logs, expose it in the analytics report, and add an optional ?routing=<mode> query parameter for backend routing experiments.

Changes

  • Read and normalize x-codemie-routing-* and x-litellm-router-* headers in usage-readers.ts
  • Normalize tiers to simple/middle/complex/reasoning and decision sources to kebab-case
  • Build per-turn modelTimeline with routing metadata; aggregate classifier/judge cost and tokens
  • Render Routing bar chart (tier height + decision-source color) in session modal
  • Add classifier cost/tokens to session modal and summary KPIs
  • Add CODEMIE_ROUTING env var / profile config to append ?routing=signal|classifier to upstream requests

Testing

  • Manual testing done: generated HTML report shows real routing data
  • npm run typecheck
  • npm run lint

Checklist

  • Code follows project standards
  • No merge conflicts with main

EPMCDME-14083

- Append ?routing=signal or ?routing=classifier to every upstream request

EPMCDME-14083
BolotnyaBoss and others added 4 commits August 28, 2026 17:57
…apture (#513)

Co-authored-by: Sviatoslav Likhtarchyk <Sviatoslav_Likhtarchyk@epam.com>
Co-authored-by: codemie-ai <codemie.ai@gmail.com>
… Routing KPI

The Routing KPI section's routedSessions filter only matched sessions with
a measured judge cost or an explicitly-unmeasured (LiteLLM) session, so any
Switchyard session routed by heuristic (decision-source: dimensions, no LLM
classifier invoked, judgeCostUSD stays null) silently fell out of the
section entirely — even though routing genuinely happened. routingCostKnown
is set (true or false) whenever a session had at least one routed turn, so
checking `!= null` catches that case too.

EPMCDME-14083
…ctor's prefix list

x-codemie-routed-model is a real Switchyard response header — confirmed against
8943 real routed turns across local transcripts, it always matches the
response body's own `model` (the actually-dispatched model) — but it doesn't
share a prefix with x-codemie-routing-*/x-codemie-requested-*, so the proxy's
CODEMIE_ROUTING_PREFIXES list silently dropped it. x_codemie_routing_capable_model,
the field usage-readers.ts and statusline.mjs relied on for the dispatched model,
was consequently never populated in any of those 8943 records; both already fell
back correctly to message.model, so this was latent rather than user-visible, but
routedModel/extractRoutedModel now resolve from real proxy data instead of by
accident.

EPMCDME-14083
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