Via vercel-ai-gateway serving deepseek/deepseek-v4.1-flash with thinking level
high, the model sporadically enters a decoding loop while emitting tool-call
markup inside the reasoning/thinking channel. After writing a normal
<parameter>…</parameter> block it never closes the call, and instead emits a
constant 23-byte cycle forever:
</parameter>\n</invoke>\n</parameter>\n</invoke>\n … (1091 repeats observed)
The same model id served by openrouter produced zero such output in the
same sessions.
- Host: pi coding agent
0.85.1 - Project:
/Users/don/dev/idfon - Provider:
vercel-ai-gateway - Model id:
deepseek/deepseek-v4.1-flash - Thinking level:
high - Window: 2026-09-14 02:45:15Z … 2026-09-14 21:24:23Z (UTC)
- 11 affected assistant messages, ~5,932 tag-loop iterations total
- 1 instance leaked into user-visible output (not just reasoning)
Two variants, both exact fixed-stride loops:
| variant | cycle | stride | seen in |
|---|---|---|---|
| A (dominant) | </parameter>\n</invoke>\n |
23 chars, 1091 consecutive cycles | msgs below |
| B | </invoke>\n</function_calls>\n |
28 chars | 8a0c4880 |
Trigger context (consistent): the model is reasoning about which command to run and starts writing a tool call inline in the thinking text, e.g.
Let me read both — this is decisive.
<parameter name="command">cd /tmp && curl -sSL ... | head -c 5500</parameter>
</invoke>
</parameter>
</invoke>
… loop …
Variant B is self-aware and still fails — the model writes
I need to stop generating malformed markup. Here is the intended tool call, correctly formed: and then emits Anthropic-namespace markup
<antml:invoke name="bash">…. <antml: appears once in this log and once in the
2026-09-13 log (possible tool-format/backend mismatch clue).
| timestamp (UTC) | message id | channel | loop iters | output tok | stopReason | responseId |
|---|---|---|---|---|---|---|
| 2026-09-14T02:45:15.250Z | 68b6cfe1 |
thinking | 65 | 3111 | toolUse | gen_01M2EWVKF92Q1FPXWZDJFAEPP7 |
| 2026-09-14T03:56:12.737Z | 8310cf45 |
thinking | 1092 | 8309 | toolUse | gen_01M2F0VZRCTZ13C74FNWRG9GMR |
| 2026-09-14T03:56:58.337Z | 26b3350d |
thinking | 102 | 4465 | stop | gen_01M2F0XV2QDJVWKTVECD1XQTJ7 |
| 2026-09-14T04:22:27.405Z | e403d264 |
thinking | 224 | 0 | aborted | gen_01M2F2CW1QNH36RYNNF31M8TJ8 |
| 2026-09-14T04:37:47.802Z | d51071a2 |
text (visible) | 220 | 3585 | stop | gen_01M2F38PYTQMADT2JQQAW60CZ2 |
| 2026-09-14T04:44:40.972Z | 1ccb4fd9 |
thinking | 53 | 560 | toolUse | gen_01M2F3NK5RXVXWSBRATQVCDD0K |
| 2026-09-14T04:47:51.007Z | dc432177 |
thinking | 89 | 0 | aborted | gen_01M2F3V75SX1CSHACFYZXRS3HB |
| 2026-09-14T04:55:30.937Z | e514ee4b |
thinking | 126 | 0 | aborted | gen_01M2F49M9P009J693H5NRBYD36 |
| 2026-09-14T05:03:21.007Z | f91a0761 |
thinking | 210 | 0 | aborted | gen_01M2F4R4KTJRY5Z3HWTD9K937T |
| 2026-09-14T05:30:40.019Z | 1013b78a |
thinking | 243 | 0 | aborted | gen_01M2F69QNA2A2H4Z1SMBEPXJQH |
| 2026-09-14T21:24:23.207Z | 8a0c4880 |
thinking | 654 (variant B) | 0 | aborted | gen_01M2GWVWT9JJQBJFTRK55PMQYV |
Sessions contain an in-session provider switch from openrouter →
vercel-ai-gateway for the same deepseek/deepseek-v4.1-flash id.
- 2026-09-14 log, switch at
2026-09-14T02:37:57.527Z; first loop at02:45:15.250Z. - The 8 assistant messages on
openrouterin that log (02:36:19Z–02:36:58Z) are clean: 0 occurrences of</invoke>,</parameter>,</function_calls>. - All 11 loop messages are
vercel-ai-gateway. Across the three affected logs, provider counts are:vercel-ai-gateway×370 assistant msgs (glitches only here) vsopenrouter×8 clean. - Caveat: the OpenRouter sample is small (~40 s of an early session), so this is a strong correlation, not proof.
8310cf45 (thinking, 1092-iteration variant A):
… channels/custom.md ##########" && curl -sSL --max-time 20 "https://eve.dev/docs/channels/custom.md" | head -c 5500</parameter>
</invoke>
</parameter>
</invoke>
</parameter>
</invoke>
… (1091 repeats) …
</parameterI have to give the solution based on the reasoning directly now.
Note the final malformed merge: </parameterI have to… — the loop is cut off
mid-tag by the model/token limit.
d51071a2 (user-visible text, 220 iterations):
Let me read a bit more of the Sessions section to get the exact session API (create, send, result).
<parameter name="command">cd /tmp && sed -n '120,178p' client.md</parameter>
</invoke>
</parameter>
</invoke>
</parameter>
</invoke>
… (219 repeats) …
8a0c4880 (variant B):
… echo "=== unstaged ==="; git status --short | grep -v "^M "</parameter>
</invoke>
</function_calls>
</invoke> understood
I need to stop generating malformed markup. Here is the intended tool call, correctly formed:
<antml:invoke name="bash">
<antml:parameter name="command">cd /Users/don/dev/idfon && git add docs/audio-media.md …
/Users/don/.pi/agent/sessions/--Users-don-dev-idfon--/2026-09-14T02-20-57-201Z_01a09db7-b3f0-76c0-89ce-d88de2c6df74.jsonl(9 of 11)/Users/don/.pi/agent/sessions/--Users-don-dev-idfon--/2026-09-14T19-41-18-878Z_01a0a170-2e9e-71f2-9b64-7295c9386347.jsonl(variant B)/Users/don/.pi/agent/sessions/--Users-don-dev-idfon--/2026-09-13T21-37-08-072Z_01a09cb3-dbe8-73bd-af78-a5efe4636c8c.jsonl(lead-up, single stray tags)
Send a multi-turn, tool-using request at thinking level high via
vercel-ai-gateway / deepseek/deepseek-v4.1-flash, where the model must
reason across several commands (e.g. "fetch these two docs, read them, then
decide X"). Look for the reasoning channel containing
</parameter>\n</invoke>\n repeated. Compare the same conversation against
openrouter with the identical model id.