Skip to content

bug: Pi provider splits trailing thinking into a second block ([thinking][text][thinking][text]) #2803

Description

@ematvey

What's broken

With a reasoning-capable model, after a long thinking block the answer text appears, then a short "tail of thinking" block appears after the answer has started, then the rest of the answer. The client shows:

[thinking]   <- long block
[text]       <- a couple of answer words
[thinking]   <- short tail
[text]       <- rest of the answer

Expected: one contiguous thinking block, then the answer.

This is provider-specific. It's not reproducible across all providers — it depends on the provider/backend emitting a reasoning delta after the final answer content has begun. We reproduce it consistently against local vLLM (see provider config below); providers that don't interleave a trailing reasoning token after the answer don't show it.

Image

Steps to reproduce

I am not 100% certain that this is easily reproducible, but, still:

  1. Use an agent whose provider is Pi (pi --mode rpc).
  2. Connect Pi to a local vLLM backend serving a reasoning model (we use DeepSeek-V4-Flash-0731).
  3. Ask a question that triggers a long reasoning phase.
  4. Watch the timeline during/after streaming.

The tail only shows when the model emits reasoning after the answer has begun — so it's backend/model dependent and won't appear on every request.

Raw Pi RPC delta stream (captured from the session, in arrival order):

THINKING_START idx=0
THINK          idx=0  (×46 deltas)
TEXT_START     idx=1
TEXT           idx=1  "There are **"
THINK          idx=0  " reasoning."      <- trailing, arrives AFTER text has started
TEXT           idx=1  (rest of answer)
THINKING_END   idx=0
TEXT_END       idx=1

Each delta carries a contentIndex — the trailing THINK still belongs to block 0 (the thinking block) even though it arrives after text block 1 began. The live stream relaying these in arrival order produces the split above. The replay path renders the same conversation as a single thinking block.

Where did this happen

iOS app

Agent provider: Custom provider (Pi)

Paseo version

0.2.5

OS version

iOS (client). Daemon backend runs on Arch Linux (kernel 7.1.5-arch1-1) in case it's relevant.

Provider configuration

Pi provider — paseo spawns pi --mode rpc --session <file> over JSONL-RPC. Model: DeepSeek-V4-Flash-0731 (reasoning-enabled) served by local vLLM behind a local gateway.

Logs

Tail of the daemon ~/.paseo/daemon.log is periodic ws_runtime_metrics during the affected turn (plus the pi --mode rpc delta capture above, which is the relevant evidence).

Screenshots or video

N/A — non-UI streaming bug; raw delta stream provided.


Same bug exists in the pi-acp (ACP) adapter

The identical interleave also affects pi-acp (the ACP adapter used by ACP hosts such as Zed): the same thinking_delta-after-text_delta pattern is relayed in arrival order, so ACP hosts show the same [thinking][text][thinking][text]. Root cause and fix are the same transport-level issue.

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