Repository navigation
Keep prose tool-tag mentions in function-tag and GLM output as text - #67
Merged
lukealonso merged 2 commits intoOct 25, 2026
Merged
Conversation
mark-yong
marked this pull request as draft
October 23, 2026 20:17
mark-yong
force-pushed
the
fix/function-tag-prose-mentions
branch
from
October 23, 2026 20:33
934cc01 to
c6fa234
Compare
mark-yong
marked this pull request as ready for review
October 23, 2026 20:34
mark-yong
marked this pull request as draft
October 25, 2026 09:59
mark-yong
force-pushed
the
fix/function-tag-prose-mentions
branch
2 times, most recently
from
October 25, 2026 10:07
12a42b6 to
1b254dc
Compare
With tools in the request, any `<tool_call>` or `<function=` in reasoning or answer text started a call. A model quoting the tag in prose, for example while discussing a parser, aborted the whole response at EOS with "tool call requires a function tag" or "incomplete function-tag tool call" (NVIDIA#30). FunctionTags now confirms an opener before leaving text: it counts only when followed by a `<function=NAME>` header and then a `<parameter` or `</function>` tag. Text that cannot match is a mention and stays in reasoning or content; an unresolved prefix is held until the next tokens decide. At finish an undecided opener is still parsed as a call, so a truncated call keeps failing at EOS and is dropped at the output limit as before. Confirmation is structural rather than requiring line start because Step 5 and MiMo templates place calls directly after content text. The check is a ToolDialect method, so it applies to every recipe using the Qwen-Coder function-tag format: Qwen 3.8, Qwen 3.8 dense, Nemotron-H, Step 5, and MiMo V2. It is also stricter than parse_tool's own header grammar on surrounding whitespace, so `<function=NAME >` and `</function >` parse as calls without the check and are mentions with it. There is no Protobuf or package change; existing packages get the fix on upgrade. The logprob retention test now feeds a valid call header, since a `<function=lookup>` followed by non-tag text is no longer a call. Validation: rebased onto bce032c and rerun on a 32-core build host. Helios library suite for this commit: 1212 passed, 21 ignored, 5 failed. Unmodified main fails the same five. Four are engram::reader staging allocations that host cannot register (ENOMEM). The fifth, package::cache::selection_tests::failed_default_clear_keeps_the_selected_entry, expects a 0o555 refs directory to reject a write and cannot fail when the suite runs as root. New tests cover answer and reasoning mentions, a mention followed by a real call, and a compact call directly after text, at every two-way split point. rustfmt --check (edition 2024) reports no formatting difference that this change introduces; the differences it still reports in chatml.rs and server/output.rs are the ones it reports on main. The four captured Qwen3.8-Flash-Next streams from NVIDIA#30 (one token per chunk, 253 KB prompt, 33 tools) were replayed through OutputPipeline: all four fail on main with "tool call requires a function tag"; on this change all parse, reasoning equals the raw reasoning with every mention kept, and all six terminal calls are recovered. Helios integration tests, Heliopause, Python, and CUDA tests were not run. Limitations: not run against a live Flare service, and Step 5, MiMo, and Nemotron-H are covered only by unit tests built from their chat templates. A complete call example in prose, fenced or not, still parses as a call; inline in reasoning, it ends reasoning and becomes a call. Gemma 4 and MiniMax keep their current behavior, as docs/api.md records. Fixes NVIDIA#30. Design-Signed-Off-By: mark-yong (AI-assisted Cursor and DeepSeek-V4.1-Flash review); design-review=babb
GLM's argument-tag parser had the same defect in answer text: any `<tool_call>` after `</think>` started a call. A quoted tag in prose aborted the response at EOS with "incomplete GLM tool call", and a quoted tag followed by a real call cut the answer short and returned a call whose function name was the intervening prose. Reasoning was unaffected because GLM's `<tool_call>` does not end reasoning. ArgumentTags now implements ToolDialect::starts_call: `<tool_call>` starts a call only when followed by a function name and then `<arg_key>` or `</tool_call>`, matching the GLM 5.3 chat template. Other text keeps the tag in the answer, and an unresolved prefix is held until later tokens decide. An undecided tag at finish is still parsed as a call, so truncated calls keep their EOS error and output-limit handling. This applies to the glm53 recipe; there is no Protobuf or package change. Validation: rebased onto bce032c and rerun on a 32-core build host. Helios library suite for this commit: 1213 passed, 21 ignored, 5 failed, the same five that fail on unmodified main (four engram::reader staging ENOMEM on that host, and a package cache test that cannot fail when the suite runs as root). The new test covers a quoted answer mention, unconfirmed and partial inline tags, and a mention followed by a real call at every two-way split point, and rustfmt --check reports no difference in the file. A probe on the unchanged parser reproduced the abort and the misnamed call for these inputs. Limitations: not run against GLM output or a live Flare service; Helios integration tests, Heliopause, Python, and CUDA tests were not run. A complete call example in prose still parses as a call. Design-Signed-Off-By: mark-yong (AI-assisted Cursor and DeepSeek-V4.1-Flash review); design-review=babb
mark-yong
force-pushed
the
fix/function-tag-prose-mentions
branch
from
October 25, 2026 10:17
1b254dc to
a631763
Compare
Contributor
Author
|
#59 (GLM argument tags) touches the same two files as this PR, |
mark-yong
marked this pull request as ready for review
October 25, 2026 21:31
tunamitom
added a commit
to tunamitom/flare-local-inference
that referenced
this pull request
Oct 27, 2026
The revert of our line-start rule dropped its regression cases along with it. Restore them on top of the structural confirmation from NVIDIA#67: - issue NVIDIA#30's minimal reproduction; - MiMo reasoning on smart that quoted an issue title mentioning <tool_call> before a real call (2026-10-23); - an inline opener with a function tag that is still prose; - a line-start call that ends reasoning implicitly; - reasoning that only quotes an opener and finishes without a call; - new: answer text that quotes an opener in prose before a real call. Every case parses whole, split at every character boundary, and fed one character at a time. The reasoning comparison ignores trailing whitespace: when a stream split falls inside a line-start opener, the parser keeps the newline before it in the reasoning, and at every other split it drops it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Oct 29, 2026
…ry JIT module ignition export of NVIDIA-Nemotron-3.5-Bolt-74B-A9B-24GB failed in "Prepare and tune kernels" with "compiler completed without publishing required artifacts" for flare.gated_rms_norm. A b12x compiler worker that planned a job kept the planning DeferredTritonKernel in the JIT's device_caches when the kernel's module was not b12x, so compiling the same job in that worker lowered nothing and published nothing. Every Ignition Triton family planned through the compiler pool is exposed. Move the flashinfer-python pin to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67), which records every planned JIT in _PLANNED_JITS, sweeps it in evict_planning_artifacts, rejects an unresolved planning stub in _run_job, and memoizes compile_compress with program_cache. The pin returns to local-inference-lab/flashinfer when the PR merges. Add a GPU-free regression test that drives a one-worker b12x CompilePool through plan-then-compile of the gated norm job and asserts the published artifact. Record the hunt's untaken follow-ups in docs/TODO.txt. Validation: tests/preparation/test_compile_pool.py 31 passed on the new pin; the new case fails with available == [False] on f91f257e. uv lock also rewrote nvidia-* dependency markers into uv's current normalized form; no package version changed besides flashinfer-python. uv sync cannot build flare-heliopause on this host (openssl-sys), so the venv was updated with uv pip install --no-deps. The full Nemotron export on this pin is pending as the change's operator-verified task. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Design-Signed-Off-By: Claude Fable 5.1 (claude-fable-5-1); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Oct 29, 2026
…on spec
Record the finished change that fixed the Nemotron export failure in "Prepare and tune kernels" ("compiler completed without publishing required artifacts"). The code landed in 24ea169, which pins FlashInfer to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67).
- The archived change carries its proposal, design, tasks with evidence and the operator approval, and a PASS-WITH-FINDINGS verification.
- openspec/specs/kernel-preparation/spec.md is the new main spec synced from its delta.
- openspec/debug/nemotron-export-compiler-publish.md is the debug ledger the root cause came from.
Validation: radflow-lint clean on the change; openspec validate --specs passes for all three main specs. The export on the repinned image passed "Prepare and tune kernels" and wrote a package. Planning records only; no code changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 3, 2026
…ry JIT module ignition export of NVIDIA-Nemotron-3.5-Bolt-74B-A9B-24GB failed in "Prepare and tune kernels" with "compiler completed without publishing required artifacts" for flare.gated_rms_norm. A b12x compiler worker that planned a job kept the planning DeferredTritonKernel in the JIT's device_caches when the kernel's module was not b12x, so compiling the same job in that worker lowered nothing and published nothing. Every Ignition Triton family planned through the compiler pool is exposed. Move the flashinfer-python pin to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67), which records every planned JIT in _PLANNED_JITS, sweeps it in evict_planning_artifacts, rejects an unresolved planning stub in _run_job, and memoizes compile_compress with program_cache. The pin returns to local-inference-lab/flashinfer when the PR merges. Add a GPU-free regression test that drives a one-worker b12x CompilePool through plan-then-compile of the gated norm job and asserts the published artifact. Record the hunt's untaken follow-ups in docs/TODO.txt. Validation: tests/preparation/test_compile_pool.py 31 passed on the new pin; the new case fails with available == [False] on f91f257e. uv lock also rewrote nvidia-* dependency markers into uv's current normalized form; no package version changed besides flashinfer-python. uv sync cannot build flare-heliopause on this host (openssl-sys), so the venv was updated with uv pip install --no-deps. The full Nemotron export on this pin is pending as the change's operator-verified task. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Design-Signed-Off-By: Claude Fable 5.1 (claude-fable-5-1); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 3, 2026
…on spec
Record the finished change that fixed the Nemotron export failure in "Prepare and tune kernels" ("compiler completed without publishing required artifacts"). The code landed in 24ea169, which pins FlashInfer to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67).
- The archived change carries its proposal, design, tasks with evidence and the operator approval, and a PASS-WITH-FINDINGS verification.
- openspec/specs/kernel-preparation/spec.md is the new main spec synced from its delta.
- openspec/debug/nemotron-export-compiler-publish.md is the debug ledger the root cause came from.
Validation: radflow-lint clean on the change; openspec validate --specs passes for all three main specs. The export on the repinned image passed "Prepare and tune kernels" and wrote a package. Planning records only; no code changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 4, 2026
…ry JIT module ignition export of NVIDIA-Nemotron-3.5-Bolt-74B-A9B-24GB failed in "Prepare and tune kernels" with "compiler completed without publishing required artifacts" for flare.gated_rms_norm. A b12x compiler worker that planned a job kept the planning DeferredTritonKernel in the JIT's device_caches when the kernel's module was not b12x, so compiling the same job in that worker lowered nothing and published nothing. Every Ignition Triton family planned through the compiler pool is exposed. Move the flashinfer-python pin to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67), which records every planned JIT in _PLANNED_JITS, sweeps it in evict_planning_artifacts, rejects an unresolved planning stub in _run_job, and memoizes compile_compress with program_cache. The pin returns to local-inference-lab/flashinfer when the PR merges. Add a GPU-free regression test that drives a one-worker b12x CompilePool through plan-then-compile of the gated norm job and asserts the published artifact. Record the hunt's untaken follow-ups in docs/TODO.txt. Validation: tests/preparation/test_compile_pool.py 31 passed on the new pin; the new case fails with available == [False] on f91f257e. uv lock also rewrote nvidia-* dependency markers into uv's current normalized form; no package version changed besides flashinfer-python. uv sync cannot build flare-heliopause on this host (openssl-sys), so the venv was updated with uv pip install --no-deps. The full Nemotron export on this pin is pending as the change's operator-verified task. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Design-Signed-Off-By: Claude Fable 5.1 (claude-fable-5-1); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 4, 2026
…on spec
Record the finished change that fixed the Nemotron export failure in "Prepare and tune kernels" ("compiler completed without publishing required artifacts"). The code landed in 24ea169, which pins FlashInfer to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67).
- The archived change carries its proposal, design, tasks with evidence and the operator approval, and a PASS-WITH-FINDINGS verification.
- openspec/specs/kernel-preparation/spec.md is the new main spec synced from its delta.
- openspec/debug/nemotron-export-compiler-publish.md is the debug ledger the root cause came from.
Validation: radflow-lint clean on the change; openspec validate --specs passes for all three main specs. The export on the repinned image passed "Prepare and tune kernels" and wrote a package. Planning records only; no code changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 4, 2026
…gment fixes Upstream 585159c names flashinfer 560fef16 in pyproject.toml and locks 776facfd, but its own f1fcb57 passes allow_bf16_atomic_reduction into the packed BF16 projection query, which FlashInfer accepts only from 42ba2f16 (its main tip, 2026-11-03); upstream's setup_preparation.py floats the dependency to @main. On either older revision the Qwen vision QuantizedProjection fails at Construct graph catalog with "unsupported packed BF16 declaration options" (probe export runs 1 and 2). On 42ba2f16 itself every moe.decode candidate fails to compile ("Value after * must be an iterable, not int"): its dense SFB partition now flattens the four-N-warp NVFP4 fragment that the dynamic MoE kernel's direct_sfb path flattens again (probe export run 3). Raydius/flashinfer@49fe544 carries 42ba2f16 plus PR NVIDIA#67's eviction commit and a one-line rank guard on that flatten; the lock is regenerated and only flashinfer-python changes. Validation: probe export on GPU 0 follows; the host compile-pool test that proves the eviction fix passes; FlashInfer's NVFP4 fused MoE live-graph tests run on GPU 1 with the guard (result in the change record). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Design-Signed-Off-By: Claude Fable 5.1 (claude-fable-5-1); design-review=a38f
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 5, 2026
Records the audit and opening of the first upstream set: owner issue NVIDIA#210, Flare PR NVIDIA#211 (mixed speculative export, DCO-signed, on 0009b89) and FlashInfer PR NVIDIA#67 refreshed to 95334c3e on 1f8ed8a3; the MoE guard PR is dropped because FlashInfer NVIDIA#71 supersedes it. verification.md is PASS. Also sweeps the untracked preclear handoff note .claude/handoff.md. Validation: documentation and workflow records only; radflow-lint clean on the change before archiving. No code, GPU, or package behavior changes. Design-Signed-Off-By: Claude Sonnet 5.5 (claude-sonnet-5-5); design-review=a38f Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 7, 2026
…r and are judged against upstream af0907d Adds the Muse Glimmer recipe row (z-lab DFlash2 drafter, 1,048,576-token context; needed until NVIDIA#229 merges), the history-drafts A/B result, and the passkey probe in the qualification row. Re-judges every row against upstream af0907d; only the FlashInfer pin moved (1f8ed8a3 to 2e4f4c2c, still without FlashInfer NVIDIA#67). Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=a38f Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 10, 2026
…ry JIT module ignition export of NVIDIA-Nemotron-3.5-Bolt-74B-A9B-24GB failed in "Prepare and tune kernels" with "compiler completed without publishing required artifacts" for flare.gated_rms_norm. A b12x compiler worker that planned a job kept the planning DeferredTritonKernel in the JIT's device_caches when the kernel's module was not b12x, so compiling the same job in that worker lowered nothing and published nothing. Every Ignition Triton family planned through the compiler pool is exposed. Move the flashinfer-python pin to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67), which records every planned JIT in _PLANNED_JITS, sweeps it in evict_planning_artifacts, rejects an unresolved planning stub in _run_job, and memoizes compile_compress with program_cache. The pin returns to local-inference-lab/flashinfer when the PR merges. Add a GPU-free regression test that drives a one-worker b12x CompilePool through plan-then-compile of the gated norm job and asserts the published artifact. Record the hunt's untaken follow-ups in docs/TODO.txt. Validation: tests/preparation/test_compile_pool.py 31 passed on the new pin; the new case fails with available == [False] on f91f257e. uv lock also rewrote nvidia-* dependency markers into uv's current normalized form; no package version changed besides flashinfer-python. uv sync cannot build flare-heliopause on this host (openssl-sys), so the venv was updated with uv pip install --no-deps. The full Nemotron export on this pin is pending as the change's operator-verified task. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Design-Signed-Off-By: Claude Fable 5.1 (claude-fable-5-1); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 10, 2026
…on spec
Record the finished change that fixed the Nemotron export failure in "Prepare and tune kernels" ("compiler completed without publishing required artifacts"). The code landed in 24ea169, which pins FlashInfer to Raydius/flashinfer@da45a722 (local-inference-lab/flashinfer PR NVIDIA#67).
- The archived change carries its proposal, design, tasks with evidence and the operator approval, and a PASS-WITH-FINDINGS verification.
- openspec/specs/kernel-preparation/spec.md is the new main spec synced from its delta.
- openspec/debug/nemotron-export-compiler-publish.md is the debug ledger the root cause came from.
Validation: radflow-lint clean on the change; openspec validate --specs passes for all three main specs. The export on the repinned image passed "Prepare and tune kernels" and wrote a package. Planning records only; no code changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=1c01
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 10, 2026
Records the audit and opening of the first upstream set: owner issue NVIDIA#210, Flare PR NVIDIA#211 (mixed speculative export, DCO-signed, on 0009b89) and FlashInfer PR NVIDIA#67 refreshed to 95334c3e on 1f8ed8a3; the MoE guard PR is dropped because FlashInfer NVIDIA#71 supersedes it. verification.md is PASS. Also sweeps the untracked preclear handoff note .claude/handoff.md. Validation: documentation and workflow records only; radflow-lint clean on the change before archiving. No code, GPU, or package behavior changes. Design-Signed-Off-By: Claude Sonnet 5.5 (claude-sonnet-5-5); design-review=a38f Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 10, 2026
…till lacks The deploy README listed only the five patch/NN branches, but deploy also carries the merged DFlash2 work. The Active table now has 13 rows with a "Still needed" verdict against upstream 0009b89: the five patches plus the qwen38_dflash recipe (only mixed prefill and yarn4 stay fork-only once upstream d68ed8f is folded in), history drafts on parallel-draft rounds, copy-depth acceptance attribution, the mixed speculative export fixes (PR NVIDIA#211), the opaque-write copy rule (probably retireable after a re-export), --recipe/--draft-model, the FlashInfer pin (until FlashInfer NVIDIA#67 merges), and the qualify/ DFlash2 tools. The warmup-retention fix moves to Retired. Includes the archived change record fork-readme-patch-inventory (Tier 1, verification PASS). Validation: documentation only; radflow-lint clean; README claims spot-checked against git (upstream cli --speculative-method dflash2, upstream qwen38 copy_offered_mask, qwen38_dflash draft revision). No tests run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=a38f
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 10, 2026
…r and are judged against upstream af0907d Adds the Muse Glimmer recipe row (z-lab DFlash2 drafter, 1,048,576-token context; needed until NVIDIA#229 merges), the history-drafts A/B result, and the passkey probe in the qualification row. Re-judges every row against upstream af0907d; only the FlashInfer pin moved (1f8ed8a3 to 2e4f4c2c, still without FlashInfer NVIDIA#67). Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=a38f Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Raydius
added a commit
to Raydius/flare-local-inference
that referenced
this pull request
Nov 11, 2026
The README patch notes on deploy judged each patch's "Still needed" verdict against upstream e774a46, the stack base. Upstream main has since moved to cbf21a1, and qualify/results/dflash2-paths-c16/ gained a measurement of A16 decode on the MXFP8-draft DFlash2 path that the patch notes did not mention. The "Still needed" line now names cbf21a1 and states that its two commits above the stack base (NVIDIA#261, WinUI model metadata; NVIDIA#260, RTX Spark revision detection and failed-download cleanup) change no file a fork patch changes; the only file both sides edit is docs/TODO.txt. The stack base stays e774a46 because the fork has not been rebased. The DFlash2 qualification tools entry now reports that A16 decode lowers code_edit on that path from 555.9 to 518.7 tok/s at concurrency 1 and the 16-client aggregate from 1,231.2 to 1,152.0 tok/s, so the fork serves the path with A16 decode off. Result: every active patch remains needed against cbf21a1, and the notes record the served configuration's A16 decision with its numbers. Evidence: the intersection of files changed in e774a46..upstream/main and e774a46..deploy contains only docs/TODO.txt. The pull requests that would retire patches, NVIDIA/spark-local-inference NVIDIA#211, NVIDIA#212 and NVIDIA#229 and local-inference-lab/flashinfer NVIDIA#67, are open as of 2026-11-11. The A16 figures are copied from qualify/results/dflash2-paths-c16/README.md (arm Q against arm QA, three trials per setting, recorded in e3ff125). No code changes; no tests run. Design-Signed-Off-By: Claude Opus 5.5 (claude-opus-5-5); design-review=cfcf Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Fixes #30. Supersedes #63.
Request
With tools in the request, any
<tool_call>or<function=in reasoning or answer text started a call. When a model quotes the tag in prose, for example while discussing a parser, the whole response aborts at EOS withtool call requires a function tagorincomplete function-tag tool call(#30). Both the reasoning variant and the answer-text variant reproduce on Qwen3.8-Flash-Next under Hermes.GLM's argument-tag parser has the same defect in answer text: a quoted
<tool_call>aborts withincomplete GLM tool call, and a quoted tag followed by a real call cuts the answer short and returns a call whose function name is the intervening prose. GLM reasoning is unaffected because its<tool_call>does not end reasoning.Change
ToolDialect::starts_call(default: always a call) lets a dialect decide whether text at an opener begins a call.ThinkReasoning(<tool_call>ending reasoning) and content-mode scanning inTaggedOutputskip mentions and continue to the next opener instead of stopping at the first match. An unresolved prefix is held until the next tokens decide.FunctionTagsconfirms an opener only when it is followed by a<function=NAME>header and then a<parameteror</function>tag. Confirmation is stricter thanparse_tool's own header grammar on surrounding whitespace:<function=NAME >and</function >parse as calls without the check and are mentions with it.ArgumentTags(GLM) confirms<tool_call>only when it is followed by a function name and then<arg_key>or</tool_call>, matching the GLM 5.3 chat template.docs/api.mddocuments the rule, its remaining limitation, and the dialects that keep their current behavior: Gemma 4, MiniMax, DeepSeek DSML and XTML.Confirmation is structural rather than requiring the opener at line start, because Step 5 and MiMo chat templates place calls directly after content text (
content<tool_call>…, and inline<tool_call><function=…>for MiMo).Scope across recipes
The check is a dialect method. The function-tag rule applies to every recipe using the Qwen3-Coder format: Qwen 3.8, Qwen 3.8 dense, Nemotron-H, Step 5 (wrapped) and MiMo V2 (compact). The GLM rule applies to GLM 5.3.
No Protobuf or package change. Existing packages pick up the fix with the new Flare build.
Validation
--features runtime-package,server, release, 32-core x86_64 build host): 1213 passed, 21 ignored, 5 failed. Unmodifiedbce032c0fails the same five (1210 passed).engram::readerstaging allocations the build host cannot register (ENOMEM).package::cache::selection_tests::failed_default_clear_keeps_the_selected_entry, expects a0o555refs directory to reject a write, which cannot fail when the suite runs as root.output::chatml::tests::prose_tool_tag_mentions_remain_text_with_registered_tools,output::chatml::tests::compact_calls_directly_after_text_still_parseandoutput::argument_tags::tests::prose_tool_tag_mentions_remain_answer_text. Together they cover answer and reasoning mentions, unconfirmed and partial inline tags, a mention followed by a real call, and a compact call directly after text, at every two-way split point.terminal_cause_preserves_incomplete_call_errors_and_never_fabricates_calls.rustfmt --check(edition 2024) reports no formatting difference this change introduces; the differences it still reports inchatml.rsandserver/output.rsare the ones it reports onmain. CI does not gatecargo fmt.<tool_call>mentioned in reasoning prose aborts the stream ("tool call requires a function tag") #30 (one token per chunk, 253 KB prompt, 33 tools) were replayed throughOutputPipeline. Onmain, all four fail withtool call requires a function tag. On this branch, all four parse, reasoning equals the raw reasoning with every quoted mention kept (2, 2, 5 and 3 mentions), and all six real terminal calls are recovered.Live Flare service, Qwen3.8 27B
The
qwen3.8-27brecipe uses the same Qwen function-tag parser as Qwen3.8 Flash. One package exported atbce032c0on an RTX PRO 6000 (SM120), served on the same GPU by Flare built frombce032c0and from this branch. 36 requests per build with one tool declared: tags quoted in answer text (<tool_call>,<function=get_weather>), reasoning that quotes the tags, ordinary tool calls, and a quoted tag followed by a real call; streaming and non-streaming/v1/chat/completionsand streaming/v1/messages, thinking on and off, three seeds.bce032c0: 24 of 24 quoted-tag requests fail. Answer-text quotes stop at the backtick withincomplete function-tag tool call; quotes in reasoning or before a call fail withtool call requires a function tag; non-streaming returns HTTP 500. All 12 ordinary tool calls succeed.END OF ANSWER(for exampleThe parser chokes on a literal `<tool_call>` tag in normal text. END OF ANSWER.). All 12 ordinary calls returnget_weather {"city":"Paris"}. 5 of 6 mention-then-call requests return the quoted sentence as content and the call; in the sixth the model omitted the<function=...>header (see Limitations).Live Flare service, Qwen3.8 Flash
One package exported at
bce032c0fromnvidia/Qwen3.8-Flash-Next-FP4-Local@b9ce18a6on an RTX PRO 6000 (SM120), served on the same GPU by the same two builds with the same 36 requests.bce032c0: 22 of 36 fail, every request in which the model wrote a tag:incomplete function-tag tool callfor answer-text quotes andtool call requires a function tagfor quotes in reasoning or before a call; non-streaming returns HTTP 500. All 12 ordinary tool calls succeed, as do 2 mention-then-call requests in which the model skipped the sentence and only called the tool.END OF ANSWER. All 12 ordinary calls returnget_weather {"city":"Paris"}. All 6 mention-then-call requests return the call; the 4 in which the model wrote the sentence return it with the quoted tag as content./v1/messagesanswers end mid-sentence before a literal</tool_call>, and one returns the model's complete example callNAME {"param_name":"value"}(see Limitations).</tool_call>would follow. A single-token continuation of one of them withignore_eosgives<|im_end|>about 0.97 and</tool_call>about 0.02, with or without tools declared.Not run: a live Flare service for Step 5, MiMo, Nemotron-H, or GLM; Helios integration tests; Heliopause, Python, and CUDA tests.
Limitations
<tool_call>is not followed by a<function=NAME>header is now returned as text instead of failing withtool call requires a function tag. The live run produced one (<tool_call>\n<parameter=city>…), returned withfinish_reason: stop. Under this rule it is indistinguishable from a mention...., failed withtool function requires parameter or closing tag. Complete example calls parse as calls, as noted above.<|tool_call>) and MiniMax (namespace-prefixed<tool_call>) keep their current behavior and would need the same treatment if a quoted opener is observed in prose. DeepSeek DSML and XTML parse through their own state machines.</tool_call>(7 of the 20 logprob requests above), so a response that discusses the tags can stop mid-sentence withfinish_reason: stop. A parser cannot recover text the model never generated; onbce032c0the same requests fail earlier with the parser error.Native servingworkflow sits ataction_requiredfor fork PRs.main's own push run onbce032c0fails atTest native CLI, and that failure reproduces locally inflare/tests/unverified_payload.rs, so a red CLI step on this branch is not caused by it.Written with AI assistance; reviewed before opening.