Skip to content

fix(gemma4 tool calls): a quote inside a string value no longer ends the value (#900) - #905

Merged
tawei-amd merged 1 commit into
mainfrom
fix/gemma4-quote-closer
Nov 1, 2026
Merged

tawei-amd merged 1 commit into
mainfrom
fix/gemma4-quote-closer

Conversation

@tawei-amd

@tawei-amd tawei-amd commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #900.

Problem

Gemma4 writes string arguments as raw text between <|"|> markers. The reader also accepts a plain " or ` as a closer (the model sometimes writes one instead of <|"|>), and took it as one whenever a , or a closer followed. Code like np.genfromtxt("train.csv", delimiter=",") or f("q","r") has that shape, so the value was cut short and the rest became a second, malformed call.

Fix

scan_gemma4_string (src/common/chat/chat_args.cpp): a plain quote now closes a string only if what follows is the next member (,key: or ,<|"|>), a closer, or the end, and the real <|"|> markers after it pair up (an odd one is the string's own closer). The real <|"|> keeps its old rule. One parser path serves every Gemma4-format model: gemma4e, gemma4-12b, gemma4e-flash, Nemotron-3.5-Bolt (same tool-call template as Google's).

Only the parser changes; no other component is touched.

Tests

  • New src/test/chat_gemma4_args (no NPU, runs on Linux CI): the Gemma4 tool-call parsing splits a call when a string argument contains a double quote (v1.0.11) #900 shapes, plain-quote closers that must keep working, streaming prefixes, a seeded random sweep. Fails 10 checks on the old code, passes now. chat_continue still passes.

  • Stress (local harness): random Gemma4-style calls with quote/comma/brace-heavy values. Old parser: 1353/2000 wrong. This PR: 0/200,000 (40 seeds), every streaming prefix and truncation checked; ASan/UBSan clean.

  • Differential on benign calls incl. plain-quote closers and a missing opener: completed parses identical to the old code.

  • Real models on the NPU (old portable build vs this PR, same 20 code-with-quotes prompts, temperature 0; a prompt passes if it gives exactly one well-formed file_write call):

    Model old parser this PR
    gemma4-it:e4b 8/20 (up to 6 calls per prompt) 20/20
    gemma4-it:e2b 8/20 (up to 4) 20/20
    gemma4-it:12b 8/20 (up to 4) 20/20
    gemma4e-flash:e4b* 8/20 (up to 6) 20/20
    gemma4e-flash:e2b* 8/20 (up to 4) 20/20
    Nemotron-3.5-Bolt-E4B 8/20 20/20

    * flash never calls a tool under tool_choice: auto (it answers in markdown), so these use tool_choice: required.
    Streamed results equal non-streamed on 10/10 (Bolt only).

  • Perf: 560 KB worst case 61 ms (old 18 ms).

Trade-offs

  • For a call that closes a string with a plain quote (malformed model output), streaming holds the arguments until the call ends; the final result is unchanged.
  • Streaming was only checked on the NPU for Bolt; 12b was run non-streaming only.

🤖 Generated with Claude Code

…value (#900)

Gemma4 writes string arguments as raw text between <|"|> markers. The reader
also accepted a plain " or ` as a closer, and took it as one whenever a comma or
a closer followed. Code such as np.genfromtxt("a.csv", delimiter=",") or
f("q","r") has that shape, so the value was cut short and the rest became a
second, malformed call.

A plain quote now closes a string only if what follows is the next member
(,key: or ,<|"|>), a closer, or the end, and the markers after it pair up (an odd
one is the string's own closer). The real <|"|> keeps its rule. Applies to every
Gemma4-format model: gemma4e, gemma4-12b, gemma4e-flash, Nemotron-3.5-Bolt.

Adds src/test/chat_gemma4_args (no NPU): the #900 shapes, the plain-quote
closers that still work, streaming prefixes, and a seeded random sweep.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@tawei-amd
tawei-amd requested a review from zaneni6 October 31, 2026 22:08
@tawei-amd
tawei-amd marked this pull request as ready for review November 1, 2026 01:08
@tawei-amd
tawei-amd merged commit 0ce8a71 into main Nov 1, 2026
38 checks passed
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.

Gemma4 tool-call parsing splits a call when a string argument contains a double quote (v1.0.11)

1 participant