Skip to content

fix(acp): coalesce trailing reasoning so answer text doesn't split the thought block - #96

Open
ematvey wants to merge 2 commits into
svkozak:mainfrom
ematvey:fix/trailing-reasoning-coalescing
Open

fix(acp): coalesce trailing reasoning so answer text doesn't split the thought block#96
ematvey wants to merge 2 commits into
svkozak:mainfrom
ematvey:fix/trailing-reasoning-coalescing

Conversation

@ematvey

@ematvey ematvey commented Aug 2, 2026

Copy link
Copy Markdown

What

Pi RPC stream can include a trailing thinking_delta after the final answer text has already started. I have this with local vLLM provider, but I suspect it is not limited to that. pi-acp relayed text_delta and thinking_delta in arrival order, so ACP clients saw:

[thinking][text][thinking][text]

(i.e. one long thinking block, a couple of answer words, then a short "tail of thinking" block, then the rest of the answer).

Root cause

Pi core is correct: it tags deltas with contentIndex and renders by block index. pi-acp's handlePiEvent dropped contentIndex and keyed blocks by arrival contiguity, so the trailing thinking_delta (contentIndex 0) was split
into a second block.

Fix

In src/acp/session.ts, hold the first text chunk briefly while thinking is present (PI_ACP_THINK_HOLD_MS, default 200ms) so a trailing reasoning delta stays in the same thought block. Flush held text before tool-call events and at turn boundaries; once thinking has clearly ended, text streams directly with no added latency.

Testing

  • Added regression test coalesces trailing thinking into the same thought block (no text split) in test/component/session-events.test.ts.
  • Full suite: 96 passed, 0 failed.
  • Fix behavior confirmed against a real pi --mode rpc delta stream.

Notes

  • Tunable via PI_ACP_THINK_HOLD_MS (ms). Set it to 0 to disable the hold (next-tick flush) — a trade-off of a small first-chunk delay for earlier text streaming in non-reasoning-heavy providers.
  • The same interleave exists in other adapters (e.g. paseo's Pi provider) and is being fixed there with the same pattern.

Copilot AI review requested due to automatic review settings August 2, 2026 16:47

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adjusts the ACP session event translation so that a late thinking_delta that arrives after answer text has begun does not split the client-visible “thought block” (avoiding [thinking][text][thinking][text] in ACP clients like Zed). It does this by briefly buffering the first answer text chunk when thinking has been seen, then flushing it once a small hold window elapses or before tool-call events.

Changes:

  • Add reasoning/text coalescing state to PiAcpSession with a configurable hold window (PI_ACP_THINK_HOLD_MS).
  • Flush held text before tool-call related assistant events and before tool execution start events.
  • Add a regression test covering the “trailing thinking after text starts” scenario.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
src/acp/session.ts Buffers initial text when thinking is present to prevent splitting thought blocks; adds flush points around tool-call/tool execution events.
test/component/session-events.test.ts Adds a regression test to ensure trailing thinking deltas coalesce into the same thought block and text is not emitted until after the hold window.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/acp/session.ts
Comment thread src/acp/session.ts
Comment thread test/component/session-events.test.ts Outdated
Address Copilot review:
- Flush held text before flushEmits in agent_settled and the prompt error path,
  so buffered chunks aren't dropped if the turn settles before the hold timer fires.
- Treat PI_ACP_THINK_HOLD_MS=0 as a disabled hold (>= 0) instead of silently
  falling back to 200ms.
- Use t.after for env cleanup in the coalescing test; add a regression test for
  flush-on-settle.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants