Skip to content

Approval for an unopened mirrored Session answers unavailable and leaves the remote turn hanging #22

Closed

Description

@Solaris136

Plugin version

0.8.18

DSH version

0.2.2-rc.1 (local), remote DSH 0.2.1-rc.2.

Area

Approval UI

Reproduction steps

  1. Connect a remote host and create a remote Session through the plugin's /api/dsh-remote endpoint (host/session/create), then send a prompt that forces a sandbox escalation, e.g. ask the agent to write /root/... with sandbox_permissions: "danger-full-access".
  2. Remote Session emits approval/asked (e.g. {"id":"...","toolName":"write","reason":"escalate sandbox to danger-full-access..."}) and the local mirror Session exists in ~/.dsh/remote/mirrors.json, but the mirrored Session has not been opened in the local UI yet (no attached local Agent/runtime).
  3. The plugin's approval bridge receives the request, finds no runtime for the local mirror and calls answerApproval(hostId, id, "unavailable").

Expected behavior

A fail-closed decision should still resolve the remote request so the remote turn continues (e.g. reject the escalation and append a denial/tool-result), instead of leaving the remote turn waiting indefinitely.

Relevant logs

  • Remote Session event log ends at approval/asked (24 events, no further events for 60s+); turn remains active.
  • Calling the remote agent's /dsh-remote-agent/api/v1/approvals/answer afterwards returns {"error":{"code":"request/invalid","message":"approval <id> is not pending"}} (with x-dsh-remote-protocol: 1 header), i.e. the unavailable answer was delivered but the ask did not resolve.
  • Code path: #handleApproval (runtime === undefined branch) answers unavailable.

Possible fix: answer rejected (or a terminal outcome) when no local runtime can present the approval, so the remote tool call resolves and the turn can finish; or document that approvals require an opened mirrored Session.

(No tokens/keys/hostnames included.)

Activity

  1. Golden-Pigeon commented on Nov 9, 2026

    @Golden-Pigeon
    Owner

    Fixed in #27.

    The plugin no longer answers a mirrored approval with unavailable while the local mirror is not ready. It keeps the approval queued until the local mirror runtime exists and a connected client is showing that mirrored Session. The approval is then handed to the ordinary native approval UI, preserving native waiting semantics: if no client shows the Session, it waits instead of being denied.

    The existing session-claim poll now doubles as a visibility heartbeat, and replayed approval ids are deduplicated so a reconnect does not create a second pending prompt. A two-client Playwright test covers the flow: both clients see the same approval, one client answers, the other client dismisses, and the remote agent receives exactly one answer.

    Thanks @Solaris136 for the report.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions