#19235: fix(telegram): tool error warnings no longer overwrite streamed replies
agents
size: S
Cluster:
Tool Execution and Error Handling
## Problem
Tool error warnings (⚠️) were overwriting the assistant's streamed reply on Telegram, leaving only the warning visible. The user would see their reply appear via streaming, then it would be replaced by the error message.
## Root Cause (Three Issues)
### 1. Mutating tool warnings suppressed when assistant replies exist
`shouldShowToolErrorWarning()` required `!hasUserFacingReply` for mutating tool errors. When the assistant produced any text, the warning was silently dropped — even though both serve different purposes.
### 2. Error payloads dropped during block streaming
When block streaming succeeded, `shouldDropFinalPayloads` dropped ALL final payloads including error warnings that were never part of the stream.
### 3. Draft stream message deleted after delivery
The `finally` block called `draftStream.clear()` (which calls `api.deleteMessage`) when `finalizedViaPreviewMessage` was false. In streaming flows, this erased the user-visible response.
## Fix
1. **`payloads.ts`**: Mutating tool errors always show warning regardless of `hasUserFacingReply`
2. **`agent-runner-payloads.ts`**: Error payloads survive `shouldDropFinalPayloads` filter
3. **`bot-message-dispatch.ts`**: Skip `draftStream.clear()` when `hasStreamedMessage` is true
## Tests
- Fixes existing failing test: *shows mutating tool errors even when assistant output exists*
- Adds 3 new tests for block streaming + error payload preservation
- All 409 existing tests pass (21 e2e + 388 unit)
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR fixes three interrelated issues where tool error warnings on Telegram would overwrite streamed assistant replies, leaving only the warning visible.
The core fixes in `agent-runner-payloads.ts` (preserving error payloads during block streaming) and `bot-message-dispatch.ts` (preventing deletion of streamed draft messages) are well-targeted and correct. The `payloads.ts` change correctly reverts an intermediate commit that suppressed mutating tool errors when replies exist.
Key concerns:
- **Over-broad read-only command classification** (`tool-mutation.ts`): The `readOnlyCmds` set includes many tools that frequently perform mutations (`git`, `python`, `docker`, `kubectl`, `npm`, `aws`, `sed`, `sqlite3`, `redis-cli`, etc.). Only the first word of the command is checked, so `git push --force`, `docker rm`, `npm run deploy`, `sed -i`, etc. would all be classified as non-mutating, potentially suppressing important failure warnings.
- **Unconditional `lastToolError` clearing** (`pi-embedded-subscribe.handlers.tools.ts`): Clearing at tool execution start may discard mutating tool errors that the existing "fail closed" logic in `handleToolExecutionEnd` was designed to preserve across multi-tool turns.
- New tests cover the block streaming payload preservation well, but there are no tests for the read-only command classification logic.
<h3>Confidence Score: 2/5</h3>
- The core streaming fixes are sound, but the over-broad read-only command classification could silently suppress error warnings for failed mutating operations.
- Score of 2 reflects that while the Telegram streaming fixes (agent-runner-payloads.ts, bot-message-dispatch.ts) are correct and well-tested, the read-only command list in tool-mutation.ts includes many tools capable of significant mutations (git, python, docker, kubectl, npm, aws, sed, sqlite3, etc.), which could suppress important failure warnings. The unconditional lastToolError clearing also undermines existing fail-closed safety logic. No tests cover the new read-only classification.
- src/agents/tool-mutation.ts (over-broad read-only classification), src/agents/pi-embedded-subscribe.handlers.tools.ts (lastToolError clearing may lose mutating failures)
<sub>Last reviewed commit: 89b25eb</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#17552: fix(agents): suppress tool error warnings when assistant already re...
by AytuncYildizli · 2026-02-15
86.0%
#17953: fix(telegram): prevent silent message loss and duplicate messages i...
by zuyan9 · 2026-02-16
85.4%
#19399: telegram: fix MEDIA false positives and partial final drop
by HOYALIM · 2026-02-17
85.0%
#19375: telegram: align tool-error summaries
by NorthyIE · 2026-02-17
84.5%
#18678: fix(telegram): preserve draft message when all final payloads are e...
by julianubico · 2026-02-16
84.2%
#18187: fix: tool summaries silently dropped when reasoningLevel is stream
by ayanesakura · 2026-02-16
84.1%
#19632: fix: suppressToolErrors now suppresses exec tool failure notifications
by Gitjay11 · 2026-02-18
83.5%
#19394: fix(agents): normalize tool call arguments dropped to {} (#19261)
by DevvGwardo · 2026-02-17
82.5%
#18992: fix: suppress spurious tool error warnings for read-only exec commands
by Phineas1500 · 2026-02-17
82.2%
#20382: fix: move suppressToolErrors check before mutating tool check
by klawdius-noodle · 2026-02-18
81.9%