Skip to content

🤖 fix: hide synthetic queued messages from the user queue UI#3684

Open
ammar-agent wants to merge 1 commit into
mainfrom
message-queue-35jw
Open

🤖 fix: hide synthetic queued messages from the user queue UI#3684
ammar-agent wants to merge 1 commit into
mainfrom
message-queue-35jw

Conversation

@ammar-agent

Copy link
Copy Markdown
Collaborator

Summary

Background bash monitor wake prompts (and other system-injected messages) no longer flash in the queued-message banner or leak into the composer: MessageQueue now tracks per-entry synthetic origin and all user-facing queue surfaces exclude synthetic entries.

Background

When a background bash monitor matched output while the owner session was actively streaming, the wake prompt was deliberately queued with queueDispatchMode: "tool-end" so it could preempt at the next tool boundary. The queue's synthetic: true flag was only used to re-tag the outgoing batch for transcript metadata — queued-message-changed emitted getMessages()/getDisplayText() verbatim. The raw system prompt ("A background bash monitor matched output. …") therefore appeared in the user queue banner until the next tool boundary flushed it, complete with Edit/Send-now affordances that could pull system text into the input box. The same gap affected every synthetic queue producer (goal continuations, workspace-turn follow-ups, compaction handler follow-ups) and restoreQueueToInput() on user interrupt.

Implementation

System vs user segregation now lives in the queue's data model:

  • MessageQueue stores QueueEntry { text, synthetic } instead of bare strings. Dispatch (produceMessage) still joins all entries in order.
  • The former getMessages()/getDisplayText() are replaced by explicitly named getUserMessages()/getUserDisplayText(), which exclude synthetic entries. The /compact and agent-skill rawCommand shortcuts only apply when no synthetic entry shares the queue, so rawCommand never misrepresents a mixed batch.
  • AgentSession builds its queued-message-changed payload through a shared buildQueuedMessageChangedEvent() (used by both live emits and the reconnect replay snapshot), so both paths only expose user-authored entries.
  • restoreQueueToInput() restores only user content; a synthetic-only queue is still cleared (canceling wake callbacks as before) but emits no restore-to-input event.

No schema or frontend changes needed: the wire format is unchanged, and the frontend's existing queuedMessages.length > 0 content check naturally hides synthetic-only queues.

Risks

Low-to-moderate: touches the queue snapshot every workspace uses for the queued banner, interrupt-restore, and reconnect replay. For all-user queues, behavior is byte-identical to before. The main behavioral change is intentional: synthetic entries disappear from display/restore surfaces while still dispatching. Covered by new unit tests for synthetic-only, mixed, and rawCommand-adjacent cases plus session-level event assertions.


Generated with mux • Model: anthropic:claude-fable-5 • Thinking: high

@ammar-agent

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

Reviewed commit: a552803a3f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant