Skip to main content
Version: Latest (unreleased)

VSR routing headers

The router uses these request and response headers for session continuity, routing observability, replay correlation, and opt-in debugging.

What appears by default​

The router splits headers across two surfaces:

  • Default surface — every routed inference response that is not served from the response cache includes x-vsr-schema-version and x-vsr-response-path. These routing keystone headers are produced by the routing pipeline, so responses answered by the Router's own handlers instead, such as GET /v1/models, omit them. The one management endpoint that does set an x-vsr-* header is POST /api/v1/routing/preview, which returns x-vsr-config-hash on a successful result. Successful routed responses can also include the final recipe, decision, confidence, algorithm, model, routing latency, cost, and replay id — the last only when Router Replay is enabled and the record was persisted. Protocol markers appear when translation occurs; protocol warnings appear only when there are warnings.
  • Configuration version — x-vsr-config-version names the version of the configuration that served the request. It rides on every routed response that is not served from the response cache, success or error, and on every response the Router answers itself, such as a block, a validation error, a cache hit or GET /v1/models. A request keeps the version it started on, even when a hot reload activates another one while it runs.
  • Debug surface — intermediate classification details, matched signals, tool-selection metrics, and x-vsr-retention-* directives appear inline only when the request sets x-vsr-debug: true. When replay is enabled, the same diagnostic context remains available through x-vsr-replay-id.

Decision and matched-signal headers additionally require all of the following:

  1. The upstream response is successful (2xx).
  2. The response was not served from the response cache.
  3. The router evaluated a routing decision or signal for the request.

Cache-hit responses can emit cache headers, but they do not re-run routing and therefore do not attach fresh matched-signal headers.

Request headers​

HeaderDirectionDescription
x-session-idrequestStable client-provided session identifier for Chat Completions. Router Learning protection uses this, together with the configured conversation identity, to reason about stay-vs-switch decisions across turns.
x-conversation-idrequestStable client-provided conversation or agent-run identifier. Router Learning protection uses this by default when scope: conversation.
x-claude-code-session-idrequestConversation identifier supplied by Claude Code on Messages API requests. x-session-id takes precedence when both are present.
x-disable-router-memoryrequestSet to true when the client already injects memory and router-managed memory would duplicate it.
x-vsr-skip-processingrequestOpts a request out of router processing when global.router.skip_processing.enabled is enabled. Use value true.
x-vsr-debugrequestOpts the request into verbose/debug response headers — headers the contract otherwise omits or demotes to replay are emitted inline for that request. Use value true.

Protocol and replay headers​

HeaderDescription
x-vsr-client-protocolInbound protocol shape seen by the router, for example openai or anthropic. Emitted only on cross-protocol handling (client protocol differs from upstream), or when x-vsr-debug is set.
x-vsr-upstream-protocolProtocol shape sent to the selected upstream backend. Emitted only on cross-protocol handling, or when x-vsr-debug is set.
x-vsr-protocol-warningsComma-separated protocol translation warnings encoded as severity;reason;field. Emitted only when warnings exist.
x-vsr-replay-idOpaque router replay record identifier for correlating a response with replay/Insights data. Emitted only when Router Replay is enabled and the record was persisted.

Response warnings​

HeaderDescription
x-vsr-response-warningsComma-separated response-quality warning codes for the completion, in fixed order: hallucination, unverified_factual, response_jailbreak. Emitted only when at least one applies.

Per-warning detail, such as hallucination spans or jailbreak confidence, is kept in the replay record instead of being expanded into response headers.

Decision headers​

Final routing facts use the default surface. Intermediate details, including Router Learning observability, require x-vsr-debug.

HeaderSurfaceDescriptionExample
x-vsr-selected-recipedefaultRouting isolation scope selected by the effective entrypoint. Omitted for concrete backend passthrough.support
x-vsr-selected-decisiondefaultFinal decision selected by the decision engine. Omitted when no decision matched and the request went to the default model; x-vsr-response-path is still upstream.complex-request
x-vsr-selected-confidencedefaultModel-derived score for the selected decision. Absent when the decision rests on policy leaves, aggregates several evidence leaves, or resolves through an error policy.0.9100
x-vsr-applied-unknown-policydefaultDecisions whose unknown result was resolved by rules.on_unknown, as decision=policy pairs. Also set on the fail_request 503.guarded=no_match
x-vsr-selected-algorithmdefaultModel-selection algorithm used after the decision matched.static
x-vsr-selected-modeldefaultLogical model alias selected by the router. When an auto-routed request matches no decision, this is the default model.reasoning-model
x-vsr-effective-input-tokensdefaultActual selected-backend rendered input tokens for the finalized automatic-output dispatch, including its chat template.512
x-vsr-effective-max-output-tokensdefaultResolved output token limit sent in that automatic-output dispatch, including reasoning. This is a budget, not consumed tokens.261632
x-vsr-routing-latency-msdefaultTime the router spent choosing the model, in milliseconds with sub-millisecond precision.0.412
x-vsr-fallback-attemptsdefaultNumber of attempts cross-model fallback made, the primary included, when a fallback candidate served the response; the same in both gateway modes. Omitted when the primary answered.2
x-vsr-selected-categorydebugDomain/category classifier result when domain routing runs.math
x-vsr-selected-reasoningdebugReasoning mode selected for the request.on
x-vsr-selected-modalitydebugModality result and optional method.AR;classifier
x-vsr-session-phasedebugProtection trace phase from the selected routing policy. Detailed learning actions are exposed through the x-vsr-learning-* headers and Router Replay.user_turn, tool_loop, provider_state
x-vsr-learning-methodsdebugRouter Learning methods summarized by this response. Full score/cache details live in Router Replay.adaptation,protection
x-vsr-learning-actionsdebugMethod-keyed compact learning actions.adaptation=propose_switch,protection=allow_switch
x-vsr-learning-scopesdebugMethod-keyed identity scopes used by learning.protection=conversation
x-vsr-learning-reasonsdebugMethod-keyed machine-readable reasons for actions.adaptation=sampled_win,protection=switch_allowed
x-vsr-injected-system-promptdebugWhether a system-prompt plugin injected text into the request.true
x-vsr-decision-rankingdebugThe matched decision the selected one beat and the comparison that settled it. Prose; parse decision_ranking in Router Replay instead. Omitted when only one decision matched.escalate-extreme over escalate-hard: equal priority 0, no comparable confidence, decision name ordering

For UI display guidance, translate x-vsr-learning-actions into user-facing phrases such as tool/protocol pinned, model switched, or learning bypassed. Fresh conversation or session-start diagnostics are usually useful only in debug views, where they should be shown as neutral status text rather than a primary route state.

The two effective-token headers are emitted together on successful upstream responses only when automatic output was resolved. They are available in the initial headers for both streaming and buffered responses. Explicit output limits, cache hits, skipped processing, and Looper responses omit them. Their values come from the final dispatch after request changes and backend rendering; they are not estimates or the model's configured maximum context length.

Matched signal headers​

Matched signal headers contain comma-separated rule names. They require x-vsr-debug and are omitted when that signal family did not match.

HeaderSignal family
x-vsr-matched-keywordskeyword
x-vsr-matched-embeddingsembedding
x-vsr-matched-domainsdomain
x-vsr-matched-fact-checkfact_check
x-vsr-matched-user-feedbackuser_feedback
x-vsr-matched-reaskreask
x-vsr-matched-preferencepreference
x-vsr-matched-languagelanguage
x-vsr-matched-contextcontext
x-vsr-context-token-countContext token estimate used by context
x-vsr-matched-structurestructure
x-vsr-matched-complexitycomplexity
x-vsr-matched-modalitymodality
x-vsr-matched-authzauthz
x-vsr-matched-jailbreakjailbreak
x-vsr-matched-piipii
x-vsr-matched-kbkb
x-vsr-matched-conversationconversation
x-vsr-matched-eventevent
x-vsr-matched-input-modalityinput_modality
x-vsr-matched-decision-modeldecision (noul and score rule names; rule:choice for choices; rule:label for each matching set or span label)

Projection headers​

HeaderDescription
x-vsr-matched-projectionsComma-separated projection mapping outputs that matched the request.

Projection scores and full projection traces are stored in router replay records rather than expanded into response headers. Use x-vsr-replay-id to inspect those details in the Dashboard or through the authenticated Router management API; public inference listeners do not serve replay records.

Retention headers​

When a matched decision emits a retention directive, debug responses expose the fields that were set. These headers help operators verify policy wiring; clients should not use them as commands.

HeaderDescription
x-vsr-retention-dropWhether the response should be excluded from response-cache retention.
x-vsr-retention-ttl-turnsDecision-level retention lifetime expressed in conversation turns.
x-vsr-retention-keep-current-modelWhether the policy asks later routing to keep the current model.
x-vsr-retention-prefer-prefixWhether prefix retention is preferred when the runtime supports it.

Unset fields are omitted. Cache hits do not emit these headers because no decision was evaluated for that response.

Cross-model KV transfer headers (issue #2976)​

When the router attempts cross-model KV reuse on a model switch, it injects request-side hints on the upstream call. The target vLLM KVConnector plugin reports the outcome on the response. These headers are internal to the router and inference pool; clients should not depend on them.

Request (router → backend):

HeaderDescription
x-vsr-kv-source-podgRPC address of the pod holding the source model's KV cache.
x-vsr-kv-cache-idOpaque session or cache identifier for the source KV block.
x-vsr-kv-mapper-idPublished mapper artifact for the source→target model pair, a ridge fit or its distilled refinement.

Response (backend → router):

HeaderDescription
x-vsr-kv-transfer-statusapplied, fallback_reprefill, or unsupported. Absent ⇒ unsupported.

Cost headers​

On a buffered (non-streaming) response, the router prices the usage the model reported with the served model's pricing configuration. This is a configured-price figure, not a provider bill. Streamed responses and models without pricing omit both headers.

HeaderSurfaceDescriptionExample
x-vsr-costdefaultUsage tokens multiplied by the served model's configured prices.0.000054
x-vsr-cost-currencydefaultCurrency of x-vsr-cost, from pricing.currency.USD

Cache and plugin headers​

x-vsr-cache-hit and x-vsr-fast-response identify an immediate response on the default surface. Cache-similarity, tool-selection metrics, and prompt-cache receipts require x-vsr-debug.

HeaderSurfaceDescription
x-vsr-cache-hitdefaultResponse came from the response cache.
x-vsr-fast-responsedefaultResponse was generated by the fast_response plugin without an upstream model call.
x-vsr-cache-similaritydebugSimilarity score from the response-cache lookup.
x-vsr-tools-strategydebugSemantic tool-selection retriever strategy used for the request.
x-vsr-tools-confidencedebugHighest tool-selection retriever similarity score.
x-vsr-tools-latency-msdebugTool-selection retriever latency in milliseconds.
x-vsr-prompt-cache-actiondebugOutcome of the prompt_cache plugin: inserted, preserved, skipped, or rejected.
x-vsr-prompt-cache-reasondebugMachine-readable reason for a non-inserted outcome: caller_markers, no_eligible_target, or unsupported_target. Omitted when the action is inserted.
x-vsr-prompt-cache-inserteddebugCount of router-inserted cache markers, at most 2 (one instruction block, one tool).
x-vsr-prompt-cache-preserveddebugCount of caller-supplied cache markers found anywhere in the request.

These headers are content-free: they report counts and outcomes, never the cached text itself, and they never claim a cache hit or provider-side savings.

Example response​

Default surface — keystone headers, final routing facts and the replay-id entry point:

HTTP/1.1 200 OK
Content-Type: application/json
x-vsr-schema-version: 2
x-vsr-response-path: upstream
x-vsr-config-version: 7
x-vsr-selected-recipe: default
x-vsr-selected-decision: complex-request
x-vsr-selected-algorithm: static
x-vsr-selected-model: reasoning-model
x-vsr-replay-id: replay_01J...

x-vsr-replay-id appears here only because Router Replay was enabled and the record was persisted. With replay disabled, or when persistence fails, the response carries the other headers and omits this one.

With x-vsr-debug: true on the request, the demoted intermediate details and matched signals are emitted inline as well:

HTTP/1.1 200 OK
Content-Type: application/json
x-vsr-schema-version: 2
x-vsr-response-path: upstream
x-vsr-selected-recipe: default
x-vsr-selected-decision: complex-request
x-vsr-selected-algorithm: static
x-vsr-selected-model: reasoning-model
x-vsr-session-phase: tool_loop
x-vsr-matched-context: long-context
x-vsr-matched-projections: use-reasoning-model
x-vsr-replay-id: replay_01J...

Compatibility and interpretation​

  • Use x-vsr-schema-version before parsing optional headers; the current value is 2. Routed inference responses not served from the response cache carry it. Responses answered by the Router's own handlers, such as GET /v1/models, never carry this header, so its absence there is expected rather than a contract violation.
  • x-vsr-matched-projections is the projection header. The singular form is not part of the public contract.
  • x-vsr-config-version counts the activations of one Router, which keeps its own configuration history. To check that replicas serve the same configuration, compare the document hash that GET /api/v1/config/hash reports as active_runtime_hash.
  • Recipe names scope local signal, projection, decision, cache, replay, metric, and learning/session identities. Use x-vsr-selected-recipe together with the local decision/signal names when correlating a response with Insights or metrics.
  • event is the public signal type used by decisions and DSL. Canonical YAML stores event rules under routing.signals.events, matching other plural signal containers.
  • Router Learning uses router-owned online state internally. Users enable online model-choice learning through global.router.learning.adaptation, enable stability protection through global.router.learning.protection, pass stable identity headers, and optionally set routing.decisions[].adaptations.mode, component modes, or adaptations.adaptation.candidate_set. scope: conversation protects one x-conversation-id; scope: session protects the broader x-session-id. The old routing.decisions[].algorithm.session_aware shape is not part of the public contract.