Proposal: prevent model-router auto routing from reusing stale text across user turns
Prevent model-router auto routing from reusing stale text across user turns
Summary
Fix model-router auto routing so that routing text is derived only from the
last role: user message. If that last user message contains no text part
(e.g. image-only multimodal content), an earlier user message must not remain as
the routing input.
Background
On current main (faccaad586a3cdc9e85dc7fa39358ff31a6453b2),
extractLastUserMessage keeps lastUserContent outside the message loop. For a
user message with array content, it updates that variable only when it sees a
type: text item.
Therefore a later user message containing only non-text parts leaves the
previous user text intact. handleJsonBody can then match an auto-routing rule
against text from an earlier turn rather than the actual last user turn.
This is a source-level diagnosis from the current implementation. Runtime red/green evidence has not yet been produced and will be required by the repository bug-fix policy before review.
Minimal diagnostic input
{
"model": "higress/auto",
"messages": [
{"role":"user","content":"Please write code"},
{"role":"assistant","content":"What should I inspect next?"},
{"role":"user","content":[{"type":"image_url","image_url":{"url":"https://example.invalid/test.png"}}]}
]
}With a routing rule matching code, the current helper can return
Please write code even though the last user message has no text. The expected
routing input is empty, so the existing defaultModel fallback should apply.
Goals
- Make the helper's result depend only on the final user message.
- Preserve current behavior for a string-valued last user message.
- Preserve current behavior for a multimodal last user message containing text.
- Preserve the current convention of returning the last text part when a single user message contains multiple text parts.
- Return an empty routing string when the last user message has no text part.
- Keep auto-routing rule ordering and default-model fallback unchanged.
Proposed behavior boundary
The fix should first identify or isolate the final role: user message, then
extract text only from that message. An equivalent implementation may reset
per-user-message state before inspecting each user turn, provided tests prove
that earlier text cannot survive a later textless user message.
Scope
Expected production changes are limited to
plugins/wasm-go/extensions/model-router/main.go and directly related tests.
A Design must define the exact runtime-verification harness before
implementation verification begins.
Non-goals
- Interpreting images, audio, files, or other non-text content for routing.
- Concatenating text across multiple user turns.
- Redesigning multimodal message schemas.
- Changing regex rules, target-model selection, or
defaultModelsemantics. - Broad refactoring of the model-router request parser.
Success criteria
- A later image-only user message produces an empty routing string even if an earlier user turn contains a matching keyword.
- The existing simple-string and multimodal-with-text cases continue to pass.
- Multiple text parts in the same final user message retain the existing last-text-part behavior.
- A request-level regression proves that stale text cannot select a routing rule and that the existing default-model fallback is used instead.
- Required baseline/fixed real proxy-Wasm evidence uses identical pinned input, records exact source/Wasm SHAs, request/response identity, logs, rerun steps, hashes, and cleanup proof.
Related work and duplicate audit
Open Issue and PR searches on 2026-09-16 found no report or implementation for
this stale cross-turn routing-text behavior in model-router.
Existing assumptions impact
The helper is already named and documented as extracting the content of the last user message. This change aligns the implementation with that existing contract rather than introducing a new routing policy.
Agent participation and approval request
A coding agent materially assisted with source analysis, duplicate checking, and preparation of this Proposal. No implementation, tests, or runtime verification for this bug fix have begun. Please review this Proposal before a Design and TASKs are authored; implementation will not begin until the Proposal and later Design receive explicit Higress maintainer approval and the implementation/verification TASKs are authorized.
Source: higress-group/higress