Skip to content

feat(dashboard): Steer a queued message into the running Turn - #2422

Merged
MathurAditya724 merged 20 commits into
mainfrom
feat/dashboard-steer-queued
Oct 30, 2026
Merged

MathurAditya724 merged 20 commits into
mainfrom
feat/dashboard-steer-queued

Conversation

@sentry-junior

@sentry-junior sentry-junior Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Stacked on #2419.

Adds a steer action to the reader's own queued web messages in the dashboard. Steering marks the message as an interrupt. When the running web Turn belongs to the same author, it reads the message at its next model boundary, in the same Turn, with its images. When another person's Turn is running, the message does not join it, so it never runs with that person's credentials. It starts the next Turn ahead of other queued input. If Junior already read the message, steering does nothing.

Before this change, the worker did not let a message that was pending at attempt start join that attempt. So a message steered mid-Turn would not arrive. Now a message that is steered after the attempt starts can join it.

API: POST /api/conversations/:id/pending-messages/steer. Only the author can steer their own queued web messages.

Also replaces the queue's remove (×) action with a delete (trash) action.

The new integration eval Dashboard Turn Steering has no recording yet. CI records it on its first run.

via adm.

--

View Session in Sentry

sentry-junior Bot and others added 3 commits October 30, 2026 04:32
Show the author avatar, image thumbnails, and one truncated line for each
queued message. Add an edit action on the reader's own queued web messages
that takes the message out of the queue and puts its text and images back
in the composer.

Co-Authored-By: adm <aditya.mathur@sentry.io>
Add a steer action on the reader's own queued web messages. It marks the
message as an interrupt, and the running web Turn of the same author reads
it at its next model boundary. A message steered while another person's
Turn runs starts the next Turn ahead of other queued input, so it never
runs with that person's credentials.

The worker now lets a message that was deferred at attempt start join the
attempt once it is steered. Steered web messages keep their stored images.

Co-Authored-By: adm <aditya.mathur@sentry.io>
Co-Authored-By: adm <aditya.mathur@sentry.io>
@vercel

vercel Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
junior-docs Ready Ready Preview Oct 30, 2026 12:13pm UTC

Request Review

sentry-junior Bot and others added 2 commits October 30, 2026 05:04
Leave the message queued when the reader leaves during the image read. If the reader leaves during the cancel, put the text in the saved draft. Do not add a leading newline when an image-only message comes back.

Co-Authored-By: adm <aditya.mathur@sentry.io>
…-queued

Co-Authored-By: adm <aditya.mathur@sentry.io>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

A dashboard steer during a Slack Turn made a web interrupt that the Slack drain tried to restore as a Slack message, so the Turn failed. The Slack drain now offers only Slack records. Other records stay pending for their own Turn.
A steered web message is an interrupt, and interrupts were selected
before the paused check. A web message steered during a yielded slice
then started a second Turn while the first Turn still waited to resume.

While a Turn is paused, web interrupts no longer start an attempt. They
stay eligible for the resumed Turn's drain, or start the next attempt.

Co-Authored-By: adm <aditya.mathur@sentry.io>
sentry-junior Bot and others added 2 commits October 30, 2026 05:59
Check that the queued images fit in the draft before the cancel. After
the cancel, images that do not fit are lost.

An image read that finishes after an edit restore now adds to the
restored images instead of replacing them. A second click during the
image read no longer starts a second edit. The author avatar has an img
role so screen readers announce its name.

Co-Authored-By: adm <aditya.mathur@sentry.io>
…-queued

# Conflicts:
#	packages/junior-dashboard/e2e/conversation-send.spec.ts

Co-Authored-By: adm <aditya.mathur@sentry.io>

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

sentry-junior Bot and others added 2 commits October 30, 2026 06:14
Queued rows are one line now, so the stack shows up to five rows. With
six or more, desktop shows four rows and a control for the rest.

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
…-queued

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
A drop or paste during the edit cancel can fill the draft after the
fit check. The queued images already left the queue, so they now win.
Draft images that no longer fit are dropped with an error.
A live poll that read the mailbox before the steer could land after it
and restore defer delivery. Then the Steer button came back.
@sentry-junior

sentry-junior Bot commented Oct 30, 2026

Copy link
Copy Markdown
Contributor Author

Screenshots

Frameshift did not run here. CI runs only for PRs into main, and this PR targets feat/dashboard-compact-queue. These come from the local dashboard e2e run (mock data) at 639306f95.

Before steer. Your own queued rows show Queued (clock), Steer, Edit, and Delete.

Queue before steer, desktop

After steering "Already read". The row shows Interrupt, and Steer is gone.

Queue after steer, desktop

Queue after steer, mobile

The image size check and the data URL for local previews were written
out in several places. Keep one helper for each so the composer, the
queue, and the transcript count and show images the same way.

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
sentry-junior Bot and others added 2 commits October 30, 2026 06:50
…-queued

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
The web steering drain rebuilt the transcript author from the Actor with
the same fields that the mailbox Turn input already holds. Pass that
author in so both transcript Messages come from one source.

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
The steer change pushed worker.ts past the 1,000-line limit. Attempt
input selection is a self-contained rule, so it moves to its own module.
Document how a dashboard steer changes mailbox delivery in the module
README.

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
MathurAditya724 added a commit that referenced this pull request Oct 30, 2026
…2419)

The queued message stack above the composer used a full email heading
and up to three lines of text per row, so a few queued messages took a
lot of space.

Each row is now one line:

- The author shows as the same avatar the conversation header uses.
Hover or focus shows the name and email.
- Image attachments show as small thumbnails that open the image
preview. Other files show a file icon with the name on hover.
- The text is one truncated line. The full text is in the hover title.

There is also a new **Edit** action. It shows only on the reader's own
accepted web messages. Edit reads the message images first, then cancels
the message in the queue, then puts the text ahead of the current draft
and adds the images back to the composer. Edit uses the existing cancel
endpoint, so:

- If Junior finishes before the reader sends the edited message, nothing
is sent, because the message is no longer in the queue.
- When the reader sends the edited message, it is a new message at the
back of the queue.
- If Junior already read the message before the cancel landed, the
cancel returns no ids. The composer shows "Junior already read that
message." and the draft does not change.

The **Steer** action (send a queued message into the running turn now)
is in the stacked follow-up #2422.

<!-- junior-request-attribution:start -->
via **adm**.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:local%3Aweb%3A6574fc16dd6453b581112066 -->

--

[View Session in
Sentry](https://sentry.sentry.io/explore/conversations/local%3Aweb%3A6574fc16dd6453b581112066/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: adm <aditya.mathur@sentry.io>
Base automatically changed from feat/dashboard-compact-queue to main October 30, 2026 12:05
sentry-junior Bot and others added 2 commits October 30, 2026 12:08
…queued

# Conflicts:
#	packages/junior-dashboard/e2e/conversation-send.spec.ts
#	packages/junior-dashboard/src/client/conversations/ComposerImages.tsx
#	packages/junior-dashboard/src/client/conversations/ConversationPage.tsx
#	packages/junior-dashboard/src/client/conversations/PendingMailboxStack.tsx

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
The steer button used the same skip icon as the interrupt status, and
the tooltips repeated the button names. Steer now uses a bolt icon, and
a steered row shows that icon with a Steered status. Each tooltip now
says what the action does. Actions use the shared icon button, so a
disabled action keeps its tooltip and delete gets the danger hover.

Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
@github-actions

Copy link
Copy Markdown
Contributor

7 screenshot changes — 7 changed · 0 added · 0 removed

Review screenshots in Frameshift

Conversation Detail · Desktop
Conversation Detail · Desktop
Changed
Conversation Event Log · Mobile
Conversation Event Log · Mobile
Changed
Conversation Fork Dialog · Desktop
Conversation Fork Dialog · Desktop
Changed
Conversation Queue Compact · Desktop
Conversation Queue Compact · Desktop
Changed
Conversation Queue Compact · Mobile
Conversation Queue Compact · Mobile
Changed
Conversation Stop Active · Desktop
Conversation Stop Active · Desktop
Changed
Show 1 more changed screenshot
Conversation Stop Active · Mobile
Conversation Stop Active · Mobile
Changed

@sentry-evals

sentry-evals Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Sentry Evals

junior-behavioral

Run Status Passed Failed Errored Cost Tokens Duration
Head Error 81 0 1 $0.79 0 544.79s

Base commit 5ac41b8 has no eval run to compare against.

junior-integration

Run Status Passed Failed Errored Cost Tokens Duration
Head Passed 103 0 0 $0.60 0 301.32s

Base commit 5ac41b8 has no eval run to compare against.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e881b41. Configure here.

@MathurAditya724
MathurAditya724 merged commit 17f44e1 into main Oct 30, 2026
49 of 50 checks passed
@MathurAditya724
MathurAditya724 deleted the feat/dashboard-steer-queued branch October 30, 2026 12:24
MathurAditya724 added a commit that referenced this pull request Oct 30, 2026
…r send (#2423)

Stacked on #2422 (which is stacked on #2419).

When Junior is idle and the queue is empty, a dashboard send used to
show in the queue stack first. Then it jumped into the transcript once
Junior read it. That jump looked laggy.

**A. Inline send.** If no Turn is running and no queued rows are
waiting, the send now goes straight to the transcript tail. It stays
there until history has the same message id, so it does not flash back
into the queue when the mailbox copy arrives.
- A failed send moves to the queue, which owns Retry. A retry stays in
the queue.
- Conversations without available history (for example, expired history)
keep the queue path. Otherwise the transcript could not show the send.
- First messages of new conversations and forks are inline.
- Inline rows have no fork action (they use the existing `pending`
transcript rows).

**B. Fast poll after send.** For 6 seconds after the latest send, the
detail query polls every 500ms. After that it uses the normal 2s / 10s
interval.

Changes:
- `conversationOutbox.ts`: `inline` flag on outbox rows,
`isInlineOutboxMessage`, `splitInlineMailboxMessages` (server copy
wins).
- `queries.ts`: fast poll window, inline cleanup waits for history,
returns `inlineMessages` apart from `pendingMessages`.
- `ConversationPage.tsx`, `TranscriptView.tsx`,
`ConversationTranscript.tsx`: decide inline at send time and pass inline
rows to the transcript.

Tests:
- `e2e/conversation-send.spec.ts`: the queue-to-history handoff test now
expects the send in the transcript, never in the queue, through mailbox
and history changes. The expired-history test keeps the queue
assertions.
- `tests/conversation-outbox.test.ts`: inline split and
failure-to-queue.
- `pnpm --filter @sentry/junior-dashboard typecheck`, `pnpm lint`,
dashboard vitest (322 tests), and `conversation-send` + `conversations`
Playwright specs (20 tests) pass locally.

<!-- junior-request-attribution:start -->
via **adm**.
<!-- junior-request-attribution:end -->

<!-- junior-session-footer:start -->
<!-- junior-conversation-id:local%3Aweb%3A6574fc16dd6453b581112066 -->

--

[View Session in
Sentry](https://sentry.sentry.io/explore/conversations/local%3Aweb%3A6574fc16dd6453b581112066/?project=4510944073809921)

<!-- junior-session-footer:end -->

---------

Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com>
Co-authored-by: adm <aditya.mathur@sentry.io>

This branch was successfully deployed

1 active deployment
Preview – junior-docs — e881b415 Deployed Oct 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: high PR risk score: high

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant