Repeated Enter in the slow /resume picker splits a session: an extension's session.send wakes an invisible context (not the visible chat), which also loses tools
- Lingua principale
- Shell
- Stelle
- 11.2k
- Fork
- 1.9k
- Merge medio
- 14h 16m
- PR unite (30g)
- 6
Descrizione
## Summary
After resuming a long-lived session, pressing **Enter multiple times in the `/resume` picker** appears to bind more than one active *context* to the same session. Afterward, when an extension calls **`session.send(...)`** to wake the session with an incoming prompt, the resulting turn is handled by a context that is **not** the one visible in the interactive TUI — so the user never sees it. The visible chat can also **lose extension-provided tools** (a tool that worked earlier later returns *"tool does not exist"*). It is a **single OS process and a single session id** throughout — the split is between contexts *within* the session, not between processes.
## Concrete setup (repro vehicle)
Observed with **[agent-relay](https://github.com/joniba/agent-relay)**, an extension that delivers messages from *other* Copilot CLI sessions into this one as prompts via `session.send` (so a peer session can "message" this session). This makes the bug easy to see: a peer sent several messages, and the agent **received and replied to each** — generating responses and calling the extension's send tool to reply. But all of that happened in the **invisible** context, so **none of it appeared in the user's visible chat**, even though the user was actively watching the session. The agent wasn't "acting on its own" — it was answering prompts the extension delivered; the bug is that those prompts (and the agent's answers) went to a context the user can't see or control.
## Environment
- Copilot CLI **v1.0.64-0** (also seen on 1.0.62–1.0.63)
- OS: Windows · Node: v24.x
- Session: long-lived — **~16 resumes** over several days, with **several auto-compactions**
## What seems to trigger it
1. The `/resume` picker is **slow to load** (waits on MCP/extension connections), so the **first Enter appears to do nothing**.
2. Pressing Enter again (and/or arrow-up/down → Enter) issues **additional resume attempts**.
3. The session log then records **multiple `session.resume` events very close together** — observed **3 within ~30 seconds**, two of them sharing the same parent event.
## Steps to reproduce (best-effort)
1. Install an extension that calls `session.send(...)` to inject prompts — e.g. [agent-relay](https://github.com/joniba/agent-relay), which delivers messages from other sessions as prompts.
2. Keep a session alive long enough to accumulate several resumes and auto-compactions.
3. Resume it via the `/resume` picker; while it's slow, **press Enter multiple times**.
4. Trigger the extension to `session.send(...)` (e.g. have another session message this one).
5. Observe where the resulting turn goes — the visible chat, or only the event log.
## Expected
`session.send(...)` wakes the **visible** chat; the injected prompt and the agent's handling appear in the interactive TUI (the normal path, cf. #2065).
## Actual
- The injected prompt is handled by a **separate, invisible context**: the turn is written to the session event log but **never rendered** in the TUI.
- The visible chat context **concurrently loses extension-provided tools** — the **same extension tool succeeded from one context and ~14 minutes later failed with *"tool does not exist"* from the visible context**, same process + session id, while the invisible context still had the tool.
- Both contexts append to the **same session event log**; the invisible turns are later **compacted out**, so neither the user nor the resumed visible context retains them.
## How it was diagnosed
- Verified a **single OS process and single session id** owned the session (process parent-chain + open-handle inspection) — ruling out duplicate processes.
- The event log showed: incoming `session.send` prompts with **no corresponding visible response**; the extension's send-tool **succeeding from one context and failing from the visible context minutes apart**; **multiple `session.resume` within 30s**; and several **compaction** events.
- Each turn carried its own fresh system prompt + task id, consistent with per-turn agent invocations sharing one session log.
## Impact
- Incoming prompts delivered by an extension are **answered by an invisible context** — responses are generated and tools are called (e.g. messaging peers back) with **no visibility or approval** in the user's chat.
- The visible session **silently loses tools** and can't see or control what the other context does in the user's name.
- Affected turns are **lost to compaction**, leaving no in-chat record.
## Related
- #2065 — extensions executing tool-calls without waking the chat (the normal "wake the chat" path this deviates from)
- #2543 — concurrent sub-agent events corrupting session state
- #1820 — tool set stripped mid-session
## Possible mitigations / asks
- **De-bounce / lock** the `/resume` action so repeated Enter can't bind multiple contexts to one session.
- Make `session.send` **always target the user-visible context**, or clearly **indicate** when a non-visible context handles a turn.
- Don't let a session's **tool set silently diverge** between contexts.
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Start at the `/resume` picker and trace how repeated Enter presses create `session.resume` events and bind contexts. Then follow `session.send(...)` through context selection and compare it with the visible TUI path described in #2065. Done means repeated resume attempts cannot split one session, injected prompts reach the visible context, and tools do not diverge between contexts.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- node.js
- Ambito
- cli
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 35/100