Skip to content

fix(tui): use role=user for model switch marker to avoid HTTP 400 on strict providers (#48338) - #54210

Merged
teknium1 merged 1 commit into
mainfrom
fix/model-switch-marker-user-role
Jun 28, 2026
Merged

fix(tui): use role=user for model switch marker to avoid HTTP 400 on strict providers (#48338)#54210
teknium1 merged 1 commit into
mainfrom
fix/model-switch-marker-user-role

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

A mid-session /model switch no longer kills the conversation with HTTP 400 on strict OpenAI-compatible providers (vLLM, Qwen).

_append_model_switch_marker() appended the post-switch context marker to session history as {"role": "system"}. The cached system prompt is prepended to the API message list (agent/conversation_loop.py), so this marker became a second system message mid-array, after prior user/assistant turns. Strict providers reject any system message that is not at the beginning of the array → HTTP 400 on the next turn.

Changes

  • tui_gateway/server.py: marker history entry + both session-DB persist sites now use role="user" instead of role="system". Matches the existing personality-overlay marker (server.py), which already appends its [System: …] text under role="user".
  • tests/tui_gateway/test_model_switch_marker_role.py: new regression coverage — marker role, content preservation, empty provider, lock path, version bump, no-op guards, and the mid-conversation shape from the report.
  • tests/test_tui_gateway_server.py: updated the existing switch test's role assertions.

Validation

Before After
Marker role system (mid-array) user
System messages in array 2 (index 0 + mid) 1 (index 0 only)
Strict-provider next turn HTTP 400 OK
Targeted tests 11 passing

repair_message_sequence() coalesces the user-role marker with adjacent user turns as needed, so alternation stays valid.

Credit

Same one-line fix was independently submitted by @liuhao1024 (#48346, earliest), @lucas-nicolas-viseo (#48355, reporter), and @Elshayib (#48361). Cleanest minimal version (#48346) salvaged here; explanatory comment from #48355 folded in. Both credited via Co-authored-by. #48361 additionally bundled unrelated custom-provider catalog changes, left out of this fix.

Infographic

Model-switch marker role fix

…strict providers (#48338)

_append_model_switch_marker() appended the post-/model-switch context marker
to session history as {"role": "system"}. The cached system prompt is
prepended to the API message list (conversation_loop.py), so this marker
became a SECOND system message mid-array after prior user/assistant turns.
Strict OpenAI-compatible providers (vLLM, Qwen) reject any system message
that is not at the beginning of the array, returning HTTP 400 and killing
the conversation on the next turn.

Flip the marker to role="user" (history entry + both session-DB persist
sites), matching the existing personality-overlay marker which already uses
role="user". repair_message_sequence() then coalesces it with adjacent user
turns as needed.

Co-authored-by: liuhao1024 <sunsky.lau@gmail.com>
Co-authored-by: Lucas Nicolas <lucas.nicolas@proton.me>
@github-actions

Copy link
Copy Markdown
Contributor

🔎 Lint report: fix/model-switch-marker-user-role vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 11658 on HEAD, 11658 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 6121 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

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

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/tui Terminal UI (ui-tui/ + tui_gateway/) P2 Medium — degraded but workaround exists provider/qwen Qwen / Alibaba Cloud (OAuth) type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants