ACP: agent updates that arrive outside a prompt are dropped — background-task turns never reach the user
- Lenguaje dominante
- Rust
- Estrellas
- 54.2k
- Forks
- 6.2k
- Merge medio
- 3 d 4 h
- PR fusionados (30 d)
- 240
Descripción
**Describe the bug**
An ACP backend can send `session/update` notifications when no `session/prompt` is in flight. goose receives them and throws them away, so any work the backend does after the turn it was asked for is lost — silently, apart from a `WARN` line.
This is routine with `claude-acp`. Claude Code answers, ends the turn, and later resumes itself when a backgrounded task completes (a build, a test run) — producing a full turn of text and tool calls that the user asked for and never sees. The session simply stops at "waiting on the build" and nothing more arrives, so it reads as the model hanging.
The drop is in the notification dispatch handler (`crates/goose/src/acp/provider.rs`). `AcpProvider::stream` breaks out of its consumer loop at `AcpUpdate::Complete` and drops the receiver, so a chunk arriving afterwards fails to send and is discarded:
```rust
if let Err(e) = tx.send(AcpUpdate::Text(text)).await {
tracing::warn!(error = %e, "undelivered ACP agent message chunk");
}
```
There is no path in goose for an assistant message that is not a response to a prompt goose sent.
---
**To Reproduce**
1. Configure the `claude-acp` provider and start a session.
2. Ask for something that makes Claude Code start a long task in the background and end its turn — e.g. "kick off a release build in the background and tell me when it finishes".
3. The turn ends with a message like "I'll report when it finishes".
4. When the build finishes, Claude Code produces its report. Nothing appears in goose.
5. `~/.local/state/goose/logs/cli//*.log` shows one `undelivered ACP agent message chunk` warning per lost chunk.
The backend's own transcript (`~/.claude/projects//*.jsonl`) contains the complete lost turn, which is how I confirmed the content exists and only goose discards it.
---
**Expected behavior**
Updates that arrive for the active session outside a prompt are surfaced as a new assistant message: persisted to the session and pushed to the UI, so the session shows the late turn as it arrives.
`set_session_title_callback` is the existing precedent for a provider pushing something into the session outside the reply stream — the same shape would work here:
- a `Provider` hook alongside `set_session_title_callback` in `crates/goose-provider-types/src/base.rs`
- the ACP provider routing `Text`/`Thought`/tool-call updates to it when no turn is live, instead of warning and dropping
- `Agent::update_provider` persisting the message and emitting it on the session update channel
- a notifier in `crates/goose/src/acp/server.rs` alongside `spawn_session_name_update_notifier` to send `agent_message_chunk` to Desktop
Whatever the mechanism, the requirement is that goose stop discarding content it has already received.
---
**Please provide the following information**
- **OS & Arch:** macOS 26.6.1 arm64
- **Interface:** UI (Desktop)
- **Version:** v2.0-rc-04-27-0 (desktop 1.45.0)
- **Extensions enabled:** developer, context7, playwright, goose docs
- **Provider & Model:** claude-acp — claude-agent-acp 0.63.0 — claude-opus-5
---
**Additional context**
Evidence from a diagnostics bundle for one affected session: the goose transcript's last message is `"Waiting on just make-ui ... I'll report as soon as it lands."`, and the log carries twelve `undelivered ACP agent message chunk` warnings over the following six seconds — the whole report turn, dropped chunk by chunk.
The warning itself only exists because of the fix for #11178, which keeps `prompt_response_tx` registered past the prompt response; before that the drop was completely silent. That fix is about chunks racing the *end* of a turn, and its bounded grace window is deliberately short. This is the separate case of chunks belonging to no turn at all, which no grace window can cover.
Related but distinct: #10433 (a dropped MCP `notifications/tools/list_changed`) is the same class of defect — a notification goose receives and discards — on a different channel.
Guía de contribución
Línea de trabajo
El bug está en `crates/goose/src/acp/provider.rs`, donde el bucle de `AcpProvider::stream` descarta las actualizaciones después de que termina un turno. Examina el controlador de dispatch de notificaciones y la advertencia de `tx.send`. Revisa `crates/goose-provider-types/src/base.rs` para ver el patrón de hook de `Provider`, similar a `set_session_title_callback`. Revisa `crates/goose/src/acp/server.rs`, donde `spawn_session_name_update_notifier` sirve como modelo para un nuevo notifier. La corrección consiste en enrutar las actualizaciones de `Text`/`Thought`/tool-call a un nuevo hook cuando no haya ningún turno activo, persistir el mensaje mediante `Agent::update_provider` y emitirlo en el canal de actualización de sesión. Haz la prueba reproduciendo el problema con `claude-acp` y comprobando en los logs la advertencia.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- rust
- Área
- ai-infra-agents, backend
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bien especificado
- Aptitud para principiantes
- 45/100