Files
DS4Server/docs/issue117-reasoning-history
..

Qwen reasoning-history rendering (#117)

Direct mode now omits echoed assistant reasoning while retaining the trained empty think scaffold. Thinking modes preserve echoed reasoning and encode historical assistant generation segments separately at <|im_start|>assistant\n<think>\n, matching the pinned server's execution route. This distinction matters when switching back from direct mode: the two newlines of an empty historical thought must remain separate tokens in thinking modes, while direct mode keeps the closed scaffold together.

The Qwen text-history adapter drops content-empty assistant messages (including reasoning-only turns) and merges consecutive user/assistant roles exactly as the server adapter does. Raw user whitespace is trimmed after merging. On merging assistants, the first assistant's reasoning is retained, matching the oracle. The HTTP adapter preserves Qwen's default reasoning echo even without tools; the selected model controls this policy. Direct rendering still drops it. Both DS4 families keep their previous policy.

Oracle and review

MTPLX 2.12.2 9882703f3105363ddc37eca9f97aa09a1d387112, unchanged Bare-Speed artifact 74559cdf34fbfc0b593de72d17e93f37fd4f9ea7, tokenizers 0.22.2. Relevant source paths: mtplx/server/openai.py (_encode_messages_uncached, _message_to_template_dict, _assistant_generation_boundaries, _reasoning_history_mode), mtplx/server/omlx_bridge/adapter.py, and the installed Qwen chat template. Qwen auto policy preserves reasoning echoes; explicit upstream preserve policy on is its legacy no-echo path. The fixtures cover both echo inputs; this change adds no new operator policy setting.

  • 304 independent cases cover direct/low/medium/xhigh, preserve echo on/off, system prompts, absent/empty/whitespace/nonempty/multiline reasoning, literal generation markers, empty assistant answers, and the resulting adjacent-user merges. Exact rendered text, IDs, history IDs, and context counts match. Compatible history+continuation concatenation stays exact; when a removed assistant causes role merging, that append is explicitly shown incompatible and the actual cached-history request path must produce the exact full request instead.
  • Actual low/medium/xhigh generations were switched to direct mode. Each produced a reasoning-only historical turn, which must be removed before merging users. All three final requests match the unmodified pinned server exactly at 62 tokens, with no stale cache reuse.
  • The issue's historical report states 68 versus 59 tokens. The current pre-change executable from commit 6507a494bc5cdfc373e5bc8056719e151766a373 independently reproduces 65 versus 59. Its failing exact-ID receipt is retained, alongside the separate empty-thinking-segment failure. The corrected reported request is exactly 59 tokens.
  • Old nonempty direct history is prefetched and saved with its actual pre-change key. Both live and disk paths miss it, and the resulting cold states are identical. An old empty-thinking history checkpoint also misses after its newline boundary changes. New direct live/disk continuations each reuse 61 tokens and produce identical complete snapshot hashes.
  • New cache-key discriminators apply only to affected Qwen histories (omitted direct reasoning, empty thinking segments, embedded generation markers, removed assistants and merged roles). Existing family and prefix controls preserve DS4 keys and unaffected Qwen histories. No checkpoint-format bump.
  • A raw rebuilt history ending in a user message cannot append another user as a separate turn. A valid committed live frontier retains its exact generated IDs even when its visible answer is empty. This distinction preserves generation continuation without treating a rebuilt prefix as an unmodified assistant frontier.
  • The older #111 compatible-cache fixture now saves the real completed-turn tag, rather than overwriting it with [111; 32]. Its reuse and complete-state assertions remain unchanged. A fabricated tag intentionally forces a raw-history rebuild and cannot verify compatible live continuation.
  • Prior #111 split/token/request controls, #116 exhaustive NFC/token/request and cache-migration controls, and both DS4 families' exact token/chat controls pass. HTTP adapter tests cover all three protocols, Qwen/DeepSeek/GLM, and tools on/off. Model execution, sampling, shaders and tensor math are unchanged.

Verification

Run tools/issue117-reference.py PINNED_MTPLX MODEL_DIRECTORY OUTPUT_DIRECTORY [MODE_SWITCH_JSON] with the reference environment. Set DS4_QWEN38_ARTIFACTS, DS4_ISSUE117_ORACLE, and a fresh DS4_ISSUE117_DIR; build the all-feature test executable and copy it outside target. Run issue117_history_renders_tokens_and_context --ignored --nocapture for CPU comparisons. Run issue117_reasoning_history_cache serially under test-supervisor 114688 60 120 --command with MTPLX_CONTEXT_COPY=0. Feed its mode-switches.json back into the independent script to verify actual generated history. Ordinary tests cover direct scaffolds, targeted key migration, void-turn merging and the HTTP preserve policy.

One full-suite attempt failed in the unrelated process-cleanup test at src/agent.rs:5550 (status=running assertion). Its unchanged isolated retry passed; the failure and isolated logs are retained. No production change or test retry was added for that failure.

Final verification: all four mandatory gates pass (320 application + 8 tool tests, 241 opt-in tests ignored). The unchanged process-cleanup test also passes in the final full suite. Compatible live/disk reuse remains 95 tokens with identical state; NFC live/disk reuse remains 93 tokens with identical state. The pre-change empty-thinking request had 87 tokens against the correct 88; this failure is reproduced by the unchanged baseline executable.