#17615: fix: don't truncate final assistant message in ACP (#15377)
stale
size: XS
Cluster:
Model Reasoning Fixes
Fix #15377 (ACP truncates final assistant chunk before end_turn). The issue was that the "final" state doesn't forward its `messageData` before emitting an `end_turn`, causing some part of the message to be silently discarded.
This change checks for the presence of `messageData` in the final state, so it can be properly passed on *before* the `end_turn` is issued.
## Summary
- Problem: #15377 (ACP truncates final assistant chunk before end_turn).
- Why it matters: Impossible to get full assistant messages in ACP clients
- What changed: Send final message chunk before `end_turn`
- What did NOT change (scope boundary): Anything else about the ACP translation.
## Change Type (select all)
- [x] Bug fix
## Scope (select all touched areas)
- [x] Integrations
## Linked Issue/PR
- Closes #15377
## User-visible / Behavior Changes
`None`
## Security Impact (required)
- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No`
- New/changed network calls? `No`
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
- If any `Yes`, explain risk + mitigation:
## Repro + Verification
### Environment
- OS: Windows
- Runtime/container: WSL
- Model/provider: z.ai
- Integration/channel (if any): ACP
- Relevant config (redacted): N/A
### Steps
1. Use `openclaw acp client` to talk to openclaw's acp gateway
2. Send a prompt that requires a multi-chunk response
### Expected
- Full response output
### Actual
- Truncated response
## Evidence
Attach at least one:
- [x] Trace/log snippets
Before:
```
OpenClaw ACP client
Session: <redacted>
Type a prompt, or "exit" to quit.
> How about now?
Working
[end_turn]
> Nope. This is me checking with OpenClaw's own ACP client, so it's definitely the openclaw issue.
Confirmed
[end_turn]
```
After:
```
[acp] ready
[acp] newSession: <redacted> -> agent:main:test
[commands] /help /commands /status /context /whoami /id /subagents /config /debug /usage /stop /restart /dock-telegram /dock-discord /dock-slack /activation /send /reset /new /think /verbose /reasoning /elevated /model /queue /bash /compact
[acp] gateway reconnected
OpenClaw ACP client
Session: <redacted>
Type a prompt, or "exit" to quit.
> Alright, I want to see if this works any better - I tweaked the code in question.
Testing the fix. This is a longer message to see if the truncation at the end is now resolved. If this entire message comes through properly, then the code change should have fixed the issue with the final state not being forwarded to the ACP client. The bug was that `handleChatEvent` was dropping the message data when `state === "final"`, so the final chunk of text was never sent. Let me know how much of this you can see on your end.
[end_turn]
```
## Human Verification (required)
What you personally verified (not just CI), and how:
- Verified scenarios: See above
- Edge cases checked: N/A
- What you did **not** verify: if there's any path where this works *without* the fix, i.e. if there's ever a final chunk with *no* messageData. But that's why I made it check for that case
## Compatibility / Migration
- Backward compatible? `Yes`)
- Config/env changes? (`No`)
- Migration needed? (`No`)
- If yes, exact upgrade steps:
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly: remove the patch
- Files/config to restore: N/A
- Known bad symptoms reviewers should watch for: N/A
## Risks and Mitigations
List only real risks for this PR. Add/remove entries as needed. If none, write `None`.
`None`
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes message truncation in ACP by sending final message chunk before `end_turn`. The `handleChatEvent` method was dropping the last chunk when `state === "final"` because it jumped straight to `finishPrompt` without checking for remaining `messageData`. This 3-line fix ensures any final chunk is forwarded via `handleDeltaEvent` before completing the turn, matching the pattern used for delta states.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk
- The fix is a targeted 3-line addition that handles an edge case without changing existing logic. The change follows the established pattern for handling message deltas, includes a defensive null check, and is verified with before/after evidence. No side effects or breaking changes possible.
- No files require special attention
<sub>Last reviewed commit: e34d4b3</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#16733: fix(ui): avoid injected newlines when tool output is hidden
by jp117 · 2026-02-15
76.1%
#12974: fix: intermittent (no output) reported by users
by vincentkoc · 2026-02-10
75.2%
#4495: Fix: emit final assistant event when reply tags hide stream
by ukeate · 2026-01-30
75.2%
#14309: fix(ui): resolve chat event session key mismatch
by justonlyforyou · 2026-02-11
74.8%
#13104: fix: persist user command message in chat transcript
by mcaxtr · 2026-02-10
74.7%
#9220: Fix: TUI drops API responses silently when runID already finalized
by vishaltandale00 · 2026-02-05
73.7%
#17316: fix: ack reaction not removed when block streaming is enabled (Tele...
by czmathew · 2026-02-15
73.7%
#17743: fix(agents): disable orphaned user message deletion that causes ses...
by clawrl3000 · 2026-02-16
73.5%
#3721: fix(ui): webchat not displaying chat responses
by maxmaxrouge-rgb · 2026-01-29
73.3%
#17179: fix: validateAnthropicTurns handles consecutive system messages for...
by Limitless2023 · 2026-02-15
73.2%