Anonymous View
Skip to content

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 #3856

@joniba

Description

@joniba

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, 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, 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

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:context-memoryContext window, memory, compaction, checkpoints, and instruction loadingarea:pluginsPlugin system, marketplace, hooks, skills, extensions, and custom agentsarea:sessionsSession management, resume, history, session picker, and session state

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions