Tool call sometimes emitted as plain JSON in `content` (missing `<|tool_call_start|>` after `</think>`) — llama.cpp + pi agent

#36
by hyge666 - opened

Summary

When using a pi coding-agent (with 4 tools: read/bash/edit/write) via llama.cpp,
the model occasionally finishes the <think> phase and then outputs the tool call as raw JSON text inside content, instead of using the expected <|tool_call_start|>[bash(...)]<|tool_call_end|> format.

In these cases:

  • llama.cpp’s lazy grammar never triggers,
  • the response ends with finish_reason: stop,
  • tool_calls is empty,
  • the agent loop halts.

Environment

  • llama.cpp b10964's llama-server
  • Try with these chat templates. This happens on both template.
    1. GGUF included chat template.
    2. new template from this PR.
  • Model: LFM2.5-8B-A1B, GGUF (q8_0, get from here)
  • Sampling: temperature 0.2, top_k 80, top_p 0.95, repeat_penalty 1.05
  • Client: pi (VS Code extension), OpenAI-compatible API

Observed behavior

The token immediately after </think> seems to determine the outcome:

turn token after </think> next token result
OK (tool call) "\n" (id 207) <|tool_call_start|> (124905) proper tool_calls emitted
NG "\n\n" (id 8) { JSON emitted in content, finish_reason: stop

For NG cases, the server logs:

Grammar still awaiting trigger after token 8

The final answer also begins with "\n\n", suggesting the model switched into “answer mode” instead of “tool-call mode”.

The JSON varies but resembles terminal-agent formats, e.g.:

{"bash": {"command": "head -50 ./Sources/Program.cs\n", "timeout": 0}}
{"analysis": "...", "plan": "...", "commands": [{"keystrokes": "find . -maxdepth 1 ...\n", "timeout": 0.5}], ...}
{"keystrokes": "cd X && ls -la\n", "duration": 0.1}

Frequency

In my tests, 2 out of 4 tool-call turns failed.
Simple requests ("list files") usually work, but multi-step ones (list *.cs → read → summarize) fail often, typically on the 1st or 2nd tool turn.

What I tried (no effect)

  • System prompt reminders ("respond with tool calls only", "do not write JSON")

Questions

  1. Is this a known behavior? Is there a recommended system prompt or harness setup for stable reasoning + tool calls in agent loops?
  2. Does the training data cover the pattern of <think> → reasoning → immediate tool call inside multi-step agent loops?

I can attach full verbose logs and the rendered prompts if useful.

Sign up or log in to comment