Repository navigation
feat(dashboard): Show idle sends in the transcript and poll fast after send - #2423
Conversation
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>
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>
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.
…r send When Junior is idle and the queue is empty, a send now appears at the transcript tail instead of passing through the queue first. A failed send still moves to the queue, which owns Retry. Conversations without available history keep the queue path. For six seconds after a send, the detail query polls every 500ms so the message reaches history quickly. Co-Authored-By: adm <aditya.mathur@sentry.io>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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>
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>
…-send Co-Authored-By: adm <aditya.mathur@sentry.io>
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>
…-send 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.
Inline sends were gated on an active conversation. Accept makes a conversation active before its Turn starts, so a follow-up still went through the queue. Gate on a started Turn instead. Inline rows now show their local images in the transcript before the server stores them, so an image send is never an empty row. Co-Authored-By: adm <aditya.mathur@sentry.io>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d268946. Configure here.
ScreenshotsFrameshift did not run here. CI runs only for PRs into Idle send with an image, before the accept returns. The message and its local image are already at the transcript tail. No queue stack is shown. |
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>
…-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>
…-send Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
The inline choice only checked the queue. An idle send leaves the queue for the transcript, so a second send before history had the first one also went inline. If the first Turn started, that row then sat in the transcript with no delete, edit, or steer. Keep sends in the queue while an earlier inline send is not in history yet. Also use the shared data URL helper for transcript image previews. 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>
…-send Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
…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>
…-send # Conflicts: # packages/junior-dashboard/src/client/conversations/ConversationTranscript.tsx Co-Authored-By: Aditya Mathur <aditya.mathur@sentry.io>
A Slack mention arrives as an interrupt, so the queue called it Steered with the steer icon. Only a dashboard steer makes a web message an interrupt. Other interrupts now show a Next step status.
…-send # Conflicts: # packages/junior-dashboard/e2e/conversation-send.spec.ts # packages/junior-dashboard/src/client/conversations/PendingMailboxStack.tsx # packages/junior-dashboard/tests/pending-mailbox-stack.test.tsx
|
7 screenshot changes — 7 changed · 0 added · 0 removed Review screenshots in Frameshift |


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.
pendingtranscript 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:inlineflag on outbox rows,isInlineOutboxMessage,splitInlineMailboxMessages(server copy wins).queries.ts: fast poll window, inline cleanup waits for history, returnsinlineMessagesapart frompendingMessages.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), andconversation-send+conversationsPlaywright specs (20 tests) pass locally.via adm.
--
View Session in Sentry