feat(widget): passive indicator for auto-resuming durable pauses#349
Open
bookernath wants to merge 2 commits into
Open
feat(widget): passive indicator for auto-resuming durable pauses#349bookernath wants to merge 2 commits into
bookernath wants to merge 2 commits into
Conversation
Branch the unified `await` event on `awaitReason`: when present, the pause resumes server-side, so render a non-interactive "working in the background" indicator (new "pause" message variant) instead of a resume affordance, and settle it once the stream resumes. Awaits without `awaitReason` keep the existing interactive local-tool/WebMCP behavior. Adds an apps/web durable-pause demo driven by mock SSE.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- Settle the durable pause in streamResponse's finally so the passive indicator clears even if the stream fails at the HTTP/read layer before another frame arrives (network drop / reader throw / abort). - Make AgentWidgetDurablePause.resolved required (every call site sets it). - Add a regression test for the stream-failure settle path.
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.
The unified
awaitSSE event can now carry anawaitReason. When present, the pause resumes on its own — so the widget shows a passive, non-interactive "working in the background" indicator (new"pause"message variant) instead of a resume button, and clears it once the stream continues.Awaits without
awaitReason(local-tool / WebMCP) keep today's interactive behavior unchanged. Suppression keys onawaitReasonbeing present (not a specific value), so future pause kinds work without a release. Indicator copy is overridable viaconfig.copy.durablePauseLabels.Try it
A new mock-driven demo: Advanced Examples → Durable Pause (
apps/web/durable-pause-demo.html), with a toggle for the two pause kinds. No backend needed.Notes
Greptile Summary
This PR adds a passive "working in the background" indicator for auto-resuming durable pauses on the unified
awaitSSE event. WhenawaitReasonis present, the widget renders a non-interactivevariant: "pause"bubble instead of a resume control, and settles it once the stream continues — with atry/finallyguard ensuring the indicator is always cleared even on HTTP-level stream failure."pause"message variant (AgentWidgetDurablePausetype,createPauseBubblecomponent) handlescrawl_pending/durable_pollwith per-reason copy overridable viaconfig.copy.durablePauseLabels, falling back gracefully to a generic label for unknown future reasons.try/finallysosettleDurablePause()runs on normal completion, network drop, or reader throw — the per-frame check settles eagerly on content/completion frames while pings are intentionally ignored.Confidence Score: 5/5
Safe to merge. The change is additive and self-contained: existing interactive tool-await paths are untouched, the new passive indicator path is well-guarded, and the SSE loop's try/finally ensures the bubble is always cleared.
The two concerns flagged in the previous round have both been addressed: the SSE loop is now wrapped in try/finally so a mid-stream network failure clears the indicator, and the stream-failure test case is included to lock in that behaviour. The core durable-pause discriminator (presence of a non-empty awaitReason) is applied consistently across the frame handler, the per-frame early-settle check, and the oracle fixture. No new logic gaps were found.
No files require special attention.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Server participant SSELoop as SSE Reader participant Settler as settleDurablePause participant UI as Pause Bubble Server->>SSELoop: "await frame (awaitReason present)" SSELoop->>UI: "emitMessage: variant=pause, resolved=false" UI-->>UI: "Show passive indicator — no resume button" Server->>SSELoop: "ping" Note over SSELoop: "ping — skip settle check" alt Stream resumes with content Server->>SSELoop: "turn_start / text frames" SSELoop->>Settler: "per-frame check triggers settle" Settler->>UI: "emitMessage: resolved=true, display none" Server->>SSELoop: "execution_complete" Note over Settler: "no-op: already null" Note over SSELoop: "finally block — no-op" else Network failure before content SSELoop->>Settler: "finally block fires on reader throw" Settler->>UI: "emitMessage: resolved=true, display none" end%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Server participant SSELoop as SSE Reader participant Settler as settleDurablePause participant UI as Pause Bubble Server->>SSELoop: "await frame (awaitReason present)" SSELoop->>UI: "emitMessage: variant=pause, resolved=false" UI-->>UI: "Show passive indicator — no resume button" Server->>SSELoop: "ping" Note over SSELoop: "ping — skip settle check" alt Stream resumes with content Server->>SSELoop: "turn_start / text frames" SSELoop->>Settler: "per-frame check triggers settle" Settler->>UI: "emitMessage: resolved=true, display none" Server->>SSELoop: "execution_complete" Note over Settler: "no-op: already null" Note over SSELoop: "finally block — no-op" else Network failure before content SSELoop->>Settler: "finally block fires on reader throw" Settler->>UI: "emitMessage: resolved=true, display none" endReviews (2): Last reviewed commit: "fix: address Greptile findings" | Re-trigger Greptile