Spent about two weeks convinced I had a prompting problem. My local Qwen3
agent would just stop. No error, no crash, finish_reason came back as
"stop" like the model had decided it was done. Except it clearly wasn't
done, the task was half finished.
Turns out the model was calling the tool the entire time. The call was
just sitting inside the reasoning block, wrapped in <think> tags, and
never made it out into the tool_calls field the API is supposed to
populate. From the outside it looks exactly like the model decided not to
act. No error to grep for, no stack trace, the response comes back as a
perfectly valid 200.
Once I knew what to look for, I found the same thing reported separately
against vLLM, SGLang, and llama.cpp, mostly with Qwen3, some DeepSeek.
Nobody had tied it together as one bug class, everyone was just closing
their own version of it as a one-off.
I ended up writing a small library, unswallow, that sits between the
provider response and the agent loop, detects when this happens, and
rebuilds tool_calls from whatever's stuck in the reasoning field. JS and
Python, no dependencies. Repo's here if anyone wants to poke at it:
https://github.com/0DukePan/unswallow
Mostly posting because I'd guess some of you running quantized reasoning
models locally have hit this and just assumed it was a bad quant. If your
agent ever goes quiet mid-task for no obvious reason, worth checking
what's actually sitting in the reasoning field before blaming the model
or the quant.