Repository navigation
Ask about a page visit an approval rule covers instead of refusing it - #855
Merged
Merged
Conversation
The browser sends a Bot's looks at a page (navigate, snapshot, scroll) straight to the computer; only changes travel through the approval route that carries the conversation. A rule that asks about a look, such as "ask before opening pages", left the gate nowhere to ask, so the route answered a bare 500 and the Bot told the person the action needed an approval flow that wasn't available. The gate now marks that case (ApprovalNeedsConversationError), the computer routes answer it as 409 needsConversation with nothing done, and the browser sends the same call again through the approval route, where it waits on the inline card like any change. Looks nothing asks about still go straight to the computer.
davidmckayv
requested review from
MikeRyanDev,
guidovizoso,
mxmzb and
tylerslaton
as code owners
October 27, 2026 20:21
Anthropic's SDK 2.3.0, which CI now installs for the AG2 harness, sends the key as Authorization: Bearer instead of x-api-key. The agent's key still reaches Anthropic; the test only looked for the old header, so it failed on every pull request. It now accepts either, and passes with Anthropic's SDK 1.17.0 and 2.3.0 alike. (cherry picked from commit a1391e7)
guidovizoso
approved these changes
Oct 27, 2026
guidovizoso
left a comment
Collaborator
There was a problem hiding this comment.
Sound fix, well scoped and well tested. Approving, with two small follow-ups:
- The inline approval wrapper now covers more tools than it needs to (
app/src/lib/copilot/approval-tools.tsx:59).tool.name.startsWith("computer_")also wrapscomputer_request_secret,computer_request_sign_inandcomputer_request_help, which never go through a rule. It works today, since with no pending requestInlineApprovaljust draws the tool's own card. But it puts the inbox query and an extra component under the secret and sign-in cards, so a later change toInlineApprovalcould break them. Suggest naming the looks explicitly (navigate, read, snapshot, screenshot, scroll, list_files, read_file), or leaving outcomputer_request_*. - Activity may read oddly. The first direct attempt still writes its refusal and failure rows, and then the retry is allowed. Worth checking that Activity doesn't show "refused" right before "Allowed once" for the same page visit.
Nit: the import reorders in server/src/approvals/types.ts and server/src/computer/routes.ts are unrelated formatter churn.
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.
What this changes
With an approval rule that asks before a Bot opens a page (for example "Ask before taking action" on
computer_navigate), the Bot did nothing and told the person the action "requires an approval flow that isn't available in this chat". The person was never shown a card.Why it happened. The browser sends a Bot's looks at a page (navigate, read, snapshot, scroll) straight to the computer. Only changes (click, type, key, run command, write file) go through
/api/approvals/computer, which carries the conversation the approval card is drawn in. The gate still decides every action, so when a rule asked about a look there was no conversation to ask in:approvalActionthrewApprovalRefusedError, and the computer route answered a bare 500 with the refusal text.The fix.
approvalActionthrowsApprovalNeedsConversationError(a subclass ofApprovalRefusedError, so existing handling is unchanged) when it has no continuation.409 { needsConversation: true, notPerformed: true }instead of a 500.failedComputerCallcarries the flag, and the approval wrapper inapproval-tools.tsxsends the same call again through/api/approvals/computer. There it waits on the inline card like any change. The inline card now wraps everycomputer_*tool, not only changes.Tests (red on
main, green here):server/tests/approval-needs-conversation.test.ts: the real gateway and routes, a gate that asks throughapprovalAction, and a real listener standing in for the computer. Asserts the 409 with the flag and that the computer was never called.app/tests/approval-tools.test.tsx:needsConversationis not misread as stale refs.Checked live on a local stack with a rule asking before
computer_navigate: the card appears, Allow once opens the page and the Bot answers from it, and Deny tells the Bot it was declined.Checks:
bun test app/tests: 1537 pass.TEST_DATABASE_URL: 585 pass.lint,format:check,typecheckandtypecheck:testsare clean.Where it runs
/api/approvals/computerpath, which reads the saved conversation from Intelligence exactly as changes do today.Boundary and audit
approvalComputerTools, then the gateway: resolve, decide, audit, act.Changelog
CHANGELOG.mdunderUnreleased.