Skip to content

Tool call parser scans inside <think> blocks, creating false-positive parse attempts from reasoning content #1592

@shanevcantwell

Description

@shanevcantwell

Environment

  • Linux (Ubuntu)
  • LM Studio 0.4.6
  • Models: qwen/qwen3.5-35b-a3b, qwen3.5-27b (both reproduce)
  • MCP tools connected (webfetch-mcp with web_search/web_fetch)

What is the bug?

LM Studio's tool call parser scans the content inside <think> blocks for tool call patterns (<function=...>, <tool_call>, <tool_call_start|>). When the model reasons about tool calling syntax as prose, the parser interprets those text patterns as actual tool call attempts, which then fail to parse.

This is distinct from #1589 and #827, where <think> tags break tool call output. Here, the parser actively enters the thinking block and finds false positives.

Reproduction

  1. Load qwen3.5-35b-a3b with reasoning enabled
  2. Connect any MCP tool (e.g., web_search)
  3. Give the model a task that causes it to reason about tool calling — e.g., debugging a tool call format issue, or researching how different models handle tool calls
  4. The model's thinking block will mention tool call syntax as prose (e.g., "some models use <function=...>, others use <tool_call>")
  5. Parser picks up these prose mentions as tool call attempts → parse failure

Observed behavior

The parser treats reasoning-block prose like:

<think>
...LM Studio's parser is treating <tool_call_start|> as raw text instead of
recognizing it as a special token that should trigger tool call parsing...
</think>

as containing actual tool call markers. The </think> boundary is not respected as a parsing firewall.

Recursive trap

This creates a self-referential failure loop:

  1. Model reasons about tool call syntax → emits tool-call-like tokens in <think> block
  2. Parser finds them → parse fails (they're prose, not well-formed calls)
  3. Error fed back to model → model reasons about the parse failure → mentions more tool call syntax
  4. Goto 2

The model explicitly recognizes the trap ("I'm getting caught in a loop where my thoughts about tool calling syntax are being interpreted as actual tool call markers") but cannot escape it — reasoning about the problem reproduces it.

Multiple format matching widens false-positive surface

The parser appears to scan for multiple tool call formats simultaneously (<tool_call>, <function=...>, <tool_call_start|>). When the model discusses format differences between models (e.g., Qwen's <tool_call> vs LFM2.5's <tool_call_start|> vs <function=...>), multiple patterns trigger in a single thinking block.

Expected behavior

The </think> boundary should be a firewall — everything between <think> and </think> should be treated as reasoning text, not scanned for tool call patterns. Ollama handles this correctly by stripping reasoning tags before tool call parsing (as noted in #1589).

Workaround

Disabling reasoning via {%- set enable_thinking = false %} in the prompt template eliminates the issue. 20+ consecutive tool calls succeed with reasoning disabled.

Evidence

Parse failure output shows reasoning content flowing into the parsed "tool call":

Failed to parse tool call: Expected "<parameter=", but got "`, `<parame" at index 14.

<tool_call>, some use `<tool_call_start|>`, some use `<function=...>`)
4. LM Studio's parser may not recognize all token formats Let me search
for more specific information... </think> <tool_call>
<function=web_search> <parameter=limit> 10 </parameter>
<parameter=query> LM Studio "reasoning" "tool call" parsing bug scan
thought block </parameter> </function> </tool_call>

The reasoning prose and the actual tool call are concatenated in the parser's view — the </think> boundary was not used as a delimiter.

Related issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions