zarvis: dismiss stale approval prompts when another client answers#345
Merged
Conversation
When a zarvis session showed a tool-approval prompt, every client that
mirrored it (the web approval dialog, the TUI minibuffer) had no way to
learn that the prompt was answered elsewhere — e.g. typed into the
session's PTY — so the dialog/minibuffer lingered after the decision.
Add a transient `SessionEvent::ToolApprovalResolved { call_id }`:
- The zarvis adapter (interactive + headless) emits it at every approval
exit — approve, deny, auto-review, unsafe-auto, stop, interrupt — so
it fires no matter how the prompt was answered.
- The daemon broadcasts it live but never persists it to the transcript,
same as BrowserPreview / AgentStatus.
- The web UI closes its approval dialog (or drops the queued entry) when
the resolved call_id matches.
- The TUI clears its minibuffer approval prompt on the same signal,
fixing the identical latent bug there.
Adds a daemon test asserting the event is broadcast but not persisted.
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.
Bug
When a zarvis session shows a tool-approval prompt, the web UI shows an approval dialog. If the user answers the prompt from the TUI (or the session's PTY, or another browser), the web dialog stays open and never closes — the decision was already made, but the passive copy lingers.
Root cause
The daemon broadcasts
ToolApprovalRequestto all clients, but there was no event signaling that an approval was resolved. A client only closed its prompt when it made the decision; it never learned that another client answered.Fix
Add a transient
SessionEvent::ToolApprovalResolved { call_id }:interactive.rs+agent.rs) emits it at every approval exit — approve / deny / auto-review→approve / unsafe-auto / stop / interrupt — so it fires regardless of how the prompt was answered (PTY keystroke ortool_decisionRPC).session.rs) broadcasts it live but never persists it to the transcript (same fast-path treatment asBrowserPreview/AgentStatus).index.html) — newresolveApproval()closes the dialog / drops the queued entry when thecall_idmatches.app.rs) — newdismiss_approval_prompt()clears the minibuffer approval prompt on the same signal, fixing the identical latent bug there.Test
tool_approval_resolved_is_not_persisted_to_transcript(broadcast-but-not-persisted).SessionEventvariant was compiler-guided across all exhaustive matches (cli rendering/rain/scroll classifiers → hidden/none).Binaries touched
agentd(daemon broadcast + bundled web UI),agent(TUI),agentd-adapter-zarvis(emits the event).Note
Verified the Rust side via tests; the browser dialog change itself wasn't exercised live in a browser (straightforward state/DOM update).
🤖 Generated with Claude Code