Repository navigation
Match llama.cpp's Seed-OSS and Cohere2 MoE parse when no thought is open - #1569
Merged
Merged
Conversation
A Seed-OSS reply to a prompt that opens no thought now has one only when it starts with `<seed:think>`, kept as generated up to the first end tag; later thinking tags are content. A Cohere2 MoE reply whose thought a handler closed for thinking off parses as after the forced-open prompt llama.cpp renders, so `Plan<|START_TEXT|>Sunny.` gives reasoning Plan, and thinking tags inside a text or action are text. Response-schema Cohere2 MoE renders close the thought with thinking off, as the Cohere2 MoE handler does. `ChatTemplateEngine.parse` takes `thoughtClosedForThinkingOff` so a final parse matches the stream. Tests pin the stream hold release from #1560. Closes #1561. Closes #1566.
ChatTemplateEngine.parse no longer takes thoughtClosedForThinkingOff: the mark it depends on is internal. The stream parser derives thinkingForcedOpen with the internal parsesThinkingForcedOpen instead.
ChatTemplateEngine.parse cannot see whether a template opened the thought, so a Seed-OSS reply that ends one it did not open parses as before, as llama.cpp parses it after such a template. The stream parses its renders through the internal parseRenderedOutput. Only ASCII whitespace may precede a leading <seed:think>, as in llama.cpp. Tests cover a stray end tag before a Cohere2 MoE body, an empty held reply, a bare start tag, and the response schema close on other formats and the multimodal path.
leehack
marked this pull request as ready for review
October 29, 2026 00:13
This was referenced Oct 29, 2026
Contributor
|
Chat app preview removed for |
This was referenced Oct 29, 2026
Merged
leehack
added a commit
that referenced
this pull request
Oct 29, 2026
…eed-OSS ASCII trim (#1572) * Pin the ASCII-only trim of the public Seed-OSS thought rule A Seed-OSS reply that starts with a no-break space before <seed:think> and ends a thought parses as after a template that opens the thought, as llama.cpp does; a Unicode trim there (mutant B12 of #1569) now fails. * Reuse a cached native bundle only while it matches its archive The build hook writes extracted.json beside each llama.cpp bundle's extracted/ directory, recording the archive's SHA-256, size and modification time and every extracted file's size. A later build reuses extracted/ only while the record matches the cached archive and the files; otherwise it extracts the archive again or downloads it. A cache without a record is extracted again once from its cached archive, offline: verified for the pinned release or a cached SHA256SUMS, as is for an override cached before the hook kept SHA256SUMS. Hook tests that seed fake extracted/ dirs now write a matching archive and marker; without them the hook would download the real bundles.
This was referenced Oct 29, 2026
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
<seed:think>after ASCII whitespace only (Cisspace, as upstream; NBSP/U+3000 do not count), kept verbatim up to the first</seed:think>, as llama.cpp 620d2225 parses it; later thinking tags stay content. Fixes #1561.Plan<|START_TEXT|>Sunny.now gives reasoningPlan/ contentSunny.: a reply that reaches a marker parses (and streams) as after the forced-open prompt llama.cpp renders.<|END_THINKING|>in a text block).parseRenderedOutput, which reads the render's internal closed-thought mark, so the engine's stream and final message match llama.cpp for marked and unmarked renders. The publicChatTemplateEngine.parsekeeps its signature and cannot see the mark, so for Seed-OSS it still ends a thought at a</seed:think>in a reply that does not start with<seed:think>, as base did and as llama.cpp does after a template that opens the thought (e.g. genkit_llamadart's parse of a custom open-thought template). Trade-off: a public parse of a stock-template reply with such a stray end tag keeps base's result, not upstream's.<seed:think>at EOF), A26 (response-schema close only for Cohere2 MoE) and A28 (its multimodal render path); changelog. (typo fixed.Root cause: Seed-OSS parsed any
<seed:think>…</seed:think>anywhere as reasoning, while llama.cpp's autoparser only takes a leading thought when the prompt opens none. Cohere2 MoE extracted thinking over the whole reply instead of stopping at the body, and the marked (thought-closed) result parsed as unforced, so text before<|START_TEXT|>was content; the response-schema render path skipped the handler that closes the thought.Production-readiness scope
Completeness checklist
chat-template-and-parsing.md,template-engine-internals.md; both changelogs. README/support matrix/examples/skills unaffected.)PR type guidance
test/fixtures/closed_thought_upstream.json(newno_thought_templatesgroup plus Cohere2 MoE open-thought cases) driven bytest/integration/core/engine/closed_thought_upstream_test.dart, and stream-parser unit tests. Affected: all platforms.Test Plan
dart run tool/prepare_workspace.dartdart format --output=none --set-exit-if-changed .dart analyzedart test -p vm -j 1 --exclude-tags local-onlydart test -p chrome --exclude-tags local-only— ran the template/engine subset (test/unit/core/template test/unit/core/engine); the change is pure Dart parsing.dart run tool/testing/check_platform_boundaries.dart;dart test -p vm test/unit/tooling/;./tool/testing/run_template_parity_suites.sh(exit 0).Matrix Evidence
static-format-analyzeroot-vm-j 1 --exclude-tags local-onlyroot-chrometest/unit/core/template test/unit/core/enginecoverage-libtemplate-paritystructured-output-adversarialhigh-risk-exact-head-independent-qa/opt/UnitySrc/personal/llama/llamadart-evidence/pr-1569/evidence-1569-70332a4.jsongguf-chat-features-smoke/llama-cpp-chat-template-smokeUpstream oracle (auditor's harness: llama.cpp 620d2225 vs llamadart engine-derived parse, public
ChatTemplateEngine.parse, and whole/bytewise/every-2-split streams; base f3706ff vs head):The 237 X and 45 Y X-Seed-open public-parse rows the audit flagged match upstream again. Visible-byte rows differing only by a trailing
<on Seed-OSS with tools (8 main, 6 X) are unchanged from the audited head.Mutation: first pass 34 mutants, 32 killed (S14 equivalent; N20 now killed). Audit pass at 1bb9148: N20, A13, A14, A26, A28 survived on correct code; all five are now killed, plus the new code's mutants (public Seed-OSS end-tag rule removed, ignoring a leading start tag, applied to every format, applied to the internal parse; Unicode
trimLeftin the handler and the stream; narrowed ASCII whitespace set): 13 of 13 killed.Review Notes
<|START_ACTION|>without tools moves from byte 9 to 16); marked Cohere2 MoE text with tools streams at EOF, as forced-open Cohere2 MoE with tools already does.<|START_TEXT|>, incomplete actions,<|END_OF_TURN_TOKEN|>after a text, and a trailing<partial differ from upstream; forced Seed-OSS (custom template opening the thought) is still not verbatim; unmarked Cohere2 MoE with an end tag before any start tag streams its first characters as content when tokens split before the end tag; Seed-OSS content keeps Dart's Unicodetrim()at its ends.High-risk regression review