Desktop shows a slash-command message twice (agent echoes the prompt into the ACP stream)
- Dominant language
- Rust
- Stars
- 54.2k
- Forks
- 6.2k
- Avg merge
- 3d 2h
- Merged PRs (30d)
- 262
Description
## Summary
In the desktop app, sending any slash command (`/plan ...`, `/goal ...`, `/summarize`, ...) shows the user's message twice in the thread.
- On builds before #10716 the two copies are glued into one user bubble with no separator, e.g. `/plan add tests/plan add tests`.
- On current `main` (after #10716) the echo carries a server-generated id, so it renders as a second, identical user bubble directly under the first.
Plain (non-slash) messages are not affected.
## Root cause
1. Every slash-command branch in `Agent::reply_impl` yields the user's own prompt back into the reply stream: `command_preamble = vec![AgentEvent::Message(user_message.clone()), ...]` and `yield AgentEvent::Message(user_message)` in `crates/goose/src/agents/agent.rs`. The normal prompt path never does this.
2. The ACP server forwards that message as a `user_message_chunk` (`handle_message_content` in `crates/goose/src/acp/server.rs`). Since #10716 the chunk carries the generated message id; before that it had none.
3. The desktop already appended the typed message to the store with a local id before calling `session/prompt` (`useChatSession.ts`). In `applyContentChunk` (`ui/desktop/src/acp/adapter/messages.ts`):
- an id-less user chunk resolves to `lastMergeableMessageWithRole(state, 'user')`, i.e. the local message, and `lastContent.text += content.text` doubles the text;
- a chunk with an unknown id is not adopted by the local message (it already has an id), so a new user message is pushed.
## Proposed fix
Client side, in `applyContentChunk`: ignore a non-steer `user_message_chunk` whose text equals the single text block of the last locally rendered user message. This covers both the id-less and the server-id shapes, leaves steer confirmation untouched (steer chunks are reconciled by id and replace text rather than append), and keeps the agent stream unchanged for the CLI and other ACP clients.
Removing the echo on the agent side would also fix it but changes what the CLI and third-party ACP clients receive, so it seems better handled separately (see #9261 for the structured-lifecycle direction).
## Verification plan
- Unit tests in `sessionNotificationAdapter.test.ts`: the echo is dropped in both shapes, a following agent chunk still lands as a separate message, and a genuine id-less user delta still merges.
- Manual: send `/plan add tests` in the desktop; the command appears once.
Contributor guide
Assessment
This issue has not been assessed yet.