Preserve shared-session viewer prompts that never reach the sharer - #14822
Draft
warp-agent-staging[bot] wants to merge 6 commits into
Draft
Preserve shared-session viewer prompts that never reach the sharer#14822warp-agent-staging[bot] wants to merge 6 commits into
warp-agent-staging[bot] wants to merge 6 commits into
Conversation
Co-Authored-By: Warp Agent <agent@warp.dev>
bnavetta
reviewed
Aug 7, 2026
Co-Authored-By: Warp Agent <agent@warp.dev>
A viewer prompt was routed to the viewer network from SharedSessionStatus, which stays ActiveViewer while the websocket reconnects. send_message_to_server then returned silently for any stage other than JoinedSuccessfully, so the prompt was neither delivered nor kept, and the input stayed frozen. Make the send observable and recoverable: - Network::send_message_to_server returns ServerMessageSendOutcome and warns with the stage, session id, and a content-free UpstreamMessage kind on every local rejection. send_agent_prompt_request now takes the caller's AgentPromptRequestId so the server's AgentPromptRequestInFlight echo can be correlated with the prompt that was staged. - Undeliverable sends, and sends the sharer does not acknowledge within five seconds, become an unlocked QueuedQueryOrigin::DisconnectedViewer row holding the prompt, its attachments, and the session/conversation it targeted. The input unfreezes immediately and a turn the submission itself started is no longer left reported as in progress. - Queue rows carry a stable request id that commit_edit re-mints, and claim_prompt_head hands a row to exactly one dispatch attempt, so racing lifecycle events and late acknowledgements cannot submit or remove a prompt twice. - A same-session rejoin retries the FIFO head, a fatal ambient end converts it to a cloud follow-up, and the replacement execution's join continues the queue. Each trigger validates the row's session and conversation token first. - Queued cloud follow-ups upload their attachments to the task definition instead of dropping them. Co-Authored-By: Warp Agent <agent@warp.dev>
The end-to-end case drives a prompt through the real input -> view -> terminal-manager -> network path with the viewer network in Stage::Reconnecting and asserts the prompt survives as one unlocked DisconnectedViewer row pinned to the session it was addressed to. Disabling the fallback-queueing branch makes it fail with the pre-fix symptom (no row at all), so it detects the defect rather than just describing the fix. Alongside it: - viewer/network_tests.rs asserts Undeliverable for every non-joined stage and a closed proxy channel, LocallyQueued only under the caller's request id, and that the drop diagnostic reports stage/session/kind while carrying none of the sentinel prompt or attachment content. - terminal_manager_tests.rs covers the joined happy path and the no-op cases for an unknown and a duplicate acknowledgement. - queued_query_tests.rs covers the unlocked disconnected-viewer row, claiming the head exactly once, restoring it in place, retargeting without duplication, the locked/command/being-edited head, and commit_edit retiring the request id. Co-Authored-By: Warp Agent <agent@warp.dev>
Co-Authored-By: Warp Agent <agent@warp.dev>
…ffer-viewer-prompts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
An Agent Mode prompt submitted by a shared-session viewer could disappear. Routing is decided from
SharedSessionStatus, which staysActiveViewerwhile the viewer websocket is reconnecting, so the prompt was handed to the viewer network — andNetwork::send_message_to_serverreturned silently for any stage other thanJoinedSuccessfully. The prompt was neither delivered nor retained, and the input could stay frozen with a staleWarping...indicator indefinitely.This makes the send observable and the prompt recoverable, using the existing queued-prompts panel as the single durable surface rather than introducing a second queue.
1. Viewer prompt acceptance is observable and correlated.
send_message_to_servernow returnsServerMessageSendOutcome::{LocallyQueued, Undeliverable}and warns on every local rejection with the network stage, the session id, and a content-freeUpstreamMessagekind (an exhaustive static label — the message itself is neverDebug-rendered, because prompt text and attachments are nested inside it).send_agent_prompt_requesttakes the caller'sAgentPromptRequestIdso the server'sAgentPromptRequestInFlightecho can be matched to the prompt that was staged.try_sendacceptance is explicitly not treated as delivery; the correlated acknowledgement is, with a five-second bound.2. Undelivered prompts land in the existing queue. A rejected send, or one the sharer does not acknowledge within five seconds, becomes an unlocked
QueuedQueryOrigin::DisconnectedViewerrow carrying the prompt, its pending attachments, and the session + server conversation token it was addressed to. The input unfreezes immediately, and a turn that this submission itself started is no longer left reported as in progress — a turn that was already running when the prompt was submitted is left alone, so a genuinely active stream keeps its indicator.3. Dispatch is transactional. Every prompt row carries a stable request id that
commit_editre-mints, andclaim_prompt_headhands a row to exactly one dispatch attempt. Racing lifecycle events cannot both submit it, a failed attempt restores it at its original position, and a late or duplicate acknowledgement can only finalize the unchanged row it belongs to — never delete a newer edit.4. Three explicit drain triggers. A same-session rejoin retries the FIFO head (after
RejoinedSuccessfullyhas flushed buffered input updates); a fatal ambient end converts the head into the cloud follow-up that starts the replacement execution; and the replacement network'sJoinedSuccessfully— notExecutionSessionReady, which fires before it connects — continues the queue. Each validates the row's session and conversation token first and leaves a non-matching head queued rather than redirecting it.5. Queued cloud follow-ups keep their attachments. The stale "cloud follow-up does not support attachments" comment and its drop are gone; the row's attachments now go through
upload_pending_attachments_to_taskbefore dispatch, and the row is restored on upload failure.Linked Issue
APP-5223. The approved spec is committed on this branch at
.agents/specs/APP-5223-buffer-disconnected-viewer-prompts.mdand is unchanged by these commits.Testing
Reproduction test, verified fail-before / pass-after.
viewer_prompt_submitted_while_reconnecting_is_preserved_as_an_editable_queue_rowdrives a prompt through the real input → view → terminal-manager → network path with the viewer network inStage::Reconnecting. Disabling the fallback-queueing branch makes it fail with exactly the pre-fix symptom (zero queue rows); it passes with the fix. It detects the defect rather than restating the fix.Also added:
viewer/network_tests.rs—Undeliverablefor every non-joined stage and for a closed proxy channel;LocallyQueuedonly under the caller's request id; the drop diagnostic reports stage/session/kind and contains none of the sentinel prompt, attachment-name, or attachment-id content; the kind label does not vary with the payload.viewer/terminal_manager_tests.rs— the joined happy path leaves no fallback row, and an unknown or duplicate acknowledgement is a no-op.queued_query_tests.rs— the disconnected-viewer row stays unlocked and deletable; the head is claimable exactly once; a restored claim returns to its original index; retargeting preserves row identity, text, and attachments without duplicating; a locked, command, or being-edited head is not claimable;commit_editretires the request id.Repository gates (all from the repo root):
./script/format --check— clean./script/check_no_inline_test_modules— cleancargo clippy --workspace --exclude warp_completer --all-targets --tests -- -D warnings— cleancargo clippy -p warp --all-targets --tests -- -D warnings— cleancargo clippy -p warp_completer --all-targets --tests -- -D warnings— cleancargo nextest run -p warp --no-fail-fast— 6225/6228 passed. The three failures (ambient_agent_headers_for_task_overrides_existing_cloud_agent_header,test_histignorespace_support_in_zsh,test_decorations_with_multibyte_chars) reproduce identically onmasterin the same sandbox and are unrelated to this change.cargo test --doc -p warp— passedStill outstanding before this is ready to merge
The spec's validation section lists 20 criteria. The ones below are not yet satisfied, and the PR is deliberately left as a draft because of them. They are listed rather than quietly dropped.
Screenshots / Videos
None yet — see criterion 20 above.
Agent Mode
CHANGELOG-BUG-FIX: Agent prompts sent while a shared session is reconnecting are no longer lost; they are kept in the queued prompts panel, the input is released immediately, and they are retried when the session reconnects or continued as a cloud follow-up.
Originating thread: https://staging.warp.dev/conversation/613eb99f-d7d2-4fd8-9d29-f7e817cdee85