Follow-up from #897's review. The recovery dispatch is now card-truth-first (specialized formats parse only their own dialect or nothing), but ToolCallFormat.Generic covers several genuinely different text dialects — Hermes/Qwen <tool_call> blocks, Llama's unmarked object and <|python_tag|>, Mistral [TOOL_CALLS] arrays — which compete by earliest marker position within the family. A Generic-family model echoing a complete foreign sub-dialect block in visible prose before its real call (e.g. a Hermes model echoing a Mistral array) can therefore still have the echo win selection.
The information that disambiguates — which sub-dialect the model's chat template actually writes — exists at the template layer (the MLX engine wires per-family parsers from exactly that truth) but is not available at the recovery seam today. Fixing this means carrying a template-derived sub-dialect hint into parse_tool_calls_from_text (from the llama.cpp runner, which can read the GGUF's template metadata, or from a resolved-capability field), then scoping the Generic marker scan to that sub-dialect the way the specialized formats are already scoped.
Severity 3 at filing: it requires a Generic-family model to emit a complete foreign-dialect block in visible prose ahead of its real call, with the named tool offered; the specialized-format and quoted-argument injection classes are all closed by #897.
🤖 Generated with Claude Code
Follow-up from #897's review. The recovery dispatch is now card-truth-first (specialized formats parse only their own dialect or nothing), but
ToolCallFormat.Genericcovers several genuinely different text dialects — Hermes/Qwen<tool_call>blocks, Llama's unmarked object and<|python_tag|>, Mistral[TOOL_CALLS]arrays — which compete by earliest marker position within the family. A Generic-family model echoing a complete foreign sub-dialect block in visible prose before its real call (e.g. a Hermes model echoing a Mistral array) can therefore still have the echo win selection.The information that disambiguates — which sub-dialect the model's chat template actually writes — exists at the template layer (the MLX engine wires per-family parsers from exactly that truth) but is not available at the recovery seam today. Fixing this means carrying a template-derived sub-dialect hint into
parse_tool_calls_from_text(from the llama.cpp runner, which can read the GGUF's template metadata, or from a resolved-capability field), then scoping the Generic marker scan to that sub-dialect the way the specialized formats are already scoped.Severity 3 at filing: it requires a Generic-family model to emit a complete foreign-dialect block in visible prose ahead of its real call, with the named tool offered; the specialized-format and quoted-argument injection classes are all closed by #897.
🤖 Generated with Claude Code