Skip to content

fix(#62): consolidate mid-conversation system messages for strict chat templates#65

Merged
Doorman11991 merged 1 commit into
masterfrom
fix/issue-62-system-msg
May 29, 2026
Merged

fix(#62): consolidate mid-conversation system messages for strict chat templates#65
Doorman11991 merged 1 commit into
masterfrom
fix/issue-62-system-msg

Conversation

@Doorman11991

Copy link
Copy Markdown
Owner

Fixes #62.

Qwen3 / Qwen3.5 chat templates under llama.cpp --jinja raise System message must be at the beginning. and llama.cpp returns HTTP 400 — but only when tools are present, since that's when it compiles the template into a tool-call grammar.

SmallCode injects role: system content mid-conversation in several places (clarifier, plan request, planner injection, path-validation warnings, skill activation, compaction summaries), so the outgoing messages array routinely had system entries at positions other than 0.

Fix

  • New src/session/message_normalizer.js#consolidateSystemMessages() collapses every system-role message into a single leading system message (order preserved, identical blocks de-duplicated) and keeps only non-system turns after it.
  • Applied in both request builders (bin/smallcode.js and bin/model_client.js chatCompletion) immediately before the request body is built, so it catches stray system messages regardless of which path injected them.

Verification

  • Instrumented the outgoing request bodies against a live Qwen3 model: every tool-bearing request now carries exactly one system message at index 0.
  • 9 new unit tests in test/message_normalizer.test.js (merge, ordering, dedup, multimodal passthrough, idempotency, edge cases).
  • Full suite: 157 passing. npm run build passes.

…plates

Qwen3/Qwen3.5 chat templates under llama.cpp --jinja raise
"System message must be at the beginning." and llama.cpp 400s when a
system-role message appears at any index but 0 — but only when tools are
present (that's when it compiles the template to build a tool-call grammar).

SmallCode injects system content mid-conversation (clarifier, plan request,
planner injection, path-validation warnings, skill activation, compaction),
so the messages array routinely had system entries past index 0.

New src/session/message_normalizer.js#consolidateSystemMessages() collapses
all system-role messages into a single leading one (order preserved, identical
blocks de-duplicated) and keeps only non-system turns after it. Applied in
both request builders (bin/smallcode.js and bin/model_client.js
chatCompletion) right before the body is sent.

Verified E2E against a Qwen3 model: every tool-bearing request now carries
exactly one system message at index 0. +9 tests; full suite 157 passing.
@Doorman11991
Doorman11991 merged commit c542a11 into master May 29, 2026
6 checks passed
@Doorman11991
Doorman11991 deleted the fix/issue-62-system-msg branch May 29, 2026 18:40
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.

llama.cpp qwen 3.5 error

1 participant