Repository navigation
Conversation
leehack
added a commit
that referenced
this pull request
Nov 9, 2026
Owner
Author
|
Landed through the 0.19.2 batch integration PR #1870 (rebase merge, one commit per constituent; this PR's pinned head was audited/CI-gated there). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
</think>before any<think>now keeps that end tag, and every thinking tag after it, as content. llama.cpp does the same at620d2225candcd959bae9.Plan.</think>Answer.used to parse as reasoningPlan.and stream differently by chunking: one char at a time gave contentPlan.Answer.plus reasoningPlan.. Every chunking now equals the final parse.parseRenderedOutput, whichparseRenderedand the stream use, takes the tags as text (thoughtTagsAreText) when the render opened no thought andendsUnopenedThoughtholds. The publicChatTemplateEngine.parsecannot see the render, so it keeps ending a thought there, as it already does for Seed-OSS.bodyStartedpath).no_thought_templatescases (finished, without tools, partial) for vendored Hermes 2 Pro, Qwen3-Coder and Qwen3 4B (thinking on).Fixes #1858
Refs #1845
Stacked on #1859 (
fix/1531-reasoning-parityat93621a38). Review and merge #1859 first; this PR's base is that branch.Production-readiness scope
</think>after a prompt that opened no thought stream the same text for every chunking, with no duplication, and match llama-server.Answer <think>X</think> more.) and a stray end tag after a leading thought (<think>A</think>B</think>C) in Hermes/Qwen3-Coder. These are older divergences, and this PR does not change them (sweep below). The pre-existing partial-parse difference for a trailing<(Use 3 <, where llama.cpp drops the<from a partial parse) is also unchanged and not recorded asupstream_partial.Completeness checklist
chat-template-and-parsing.md,template-engine-internals.mdand theparseRendereddartdoc are updated. No public API or skills change.PR type guidance
extractThinkingtreats an end tag before any start tag as the end of a thought the prompt opened. The parse then reclassifies text the stream has already sent as content, so the final reconciliation adds it again as reasoning and skips the content delta (prefix mismatch). llama.cpp takes a thought only where the prompt opened one or at the start of the reply. The fix gives the rendered parse and the stream the same rule. It applies only when the render opened no thought: forced-open, closed (template's empty thought) and closed-for-thinking-off renders are unchanged.Test Plan
dart run tool/prepare_workspace.dart(clean worktree)dart format --output=none --set-exit-if-changed .(0 changed)dart analyze(no issues);check_platform_boundaries.dartOKdart test -p vm -j 1 --exclude-tags local-only: full VM suite ran under coverage (11860 passed). The only failures werewindows_registry_qualification_test.dart(6,ProcessException: No such file or directory, which fails the same way at base93621a38on this Mac) andqwen_content_contract_test.dartthinking=true (3). That test fed a syntheticCheck values.</think>with no start tag. It now feeds<think>Check values.</think>, which is what the native LiteRT channel assembler emits (it always writes the start tag). Affected suites rerun at head: 3957 passed; markdown-selected suites: 729 passed.dart test -p chrome --exclude-tags local-only: the changed Chrome-capable tests (stream parser, engine, LiteRT Qwen contract, thinking utils): 557 passed. CI runs the full shards.coverage-libmatrix row: LCOV line coverage 93.64% (threshold 70)../tool/testing/run_template_parity_suites.sh(74/103/1865/10/79 passed), plus the oracle sweeps below.Matrix Evidence
models/templatesplus 18 vendoredtest/fixtures/templatescd959bae9(common_chat_sessionfeed/finish, andcommon_chat_peg_parsewithis_partial). Base93621a38vs head, 0 match-to-mismatch transitions in every corpus (oracle parity and stream-equals-parse). See the sweep table below.</think>after a prompt that opened no thought, which a real Qwen3/Hermes run does not produce on demand. Evidence is primary upstream emissions (oracle at the pin) plus durable fixtures.Sweeps (base
93621a38→ head; "oracle" = parse and every chunking equal llama.cpp; "self" = every chunking equals the final parse):Hermes and Qwen3-Coder non-forced renders have no stream-vs-parse mismatch left in these corpora. Remaining oracle differences there are the #1865 shapes and cross-format tool envelopes. Evidence:
llamadart-evidence/issue-1858/(harness, per-case JSONL for base and head, summaries, mutants).Mutations (targeted VM suites, production restored after each):
promptOpensNoThought && endsUnopenedThought→||endsUnopenedThoughtignores start-tag order / U2 any start tag disables itA
!_usesPegParserguard in the stream condition was removed after review: with a PEG parser these formats never reach the split (parsed mode with tools, the leading-thought path without), and the head sweeps are byte-identical with and without it.Review Notes
4b4934a4bcef. CI runs only on PRs intomain, so it was dispatched on this branch: run 42657556794, success (26 passed, 6 skipped by selection, 0 failed).High-risk regression review
4b4934a4bcef/93621a3813ab(Keep a trailing partial tag in an unended thought, as llama.cpp v0.9.0 does #1859 head; that PR's base is87aaec616)