Repository navigation
Stop mistaking a filled-in form for a payment, and stop refusing a browser step while it saves - #836
Merged
Conversation
safetyRequirement read a computer_type call's typed text along with its target, so the payments rule matched words in the content: a CRM note about a customer's "purchase orders" or a source field reading "Business Wire" was handed back to the person as a money movement, in the middle of filling in a form. Typed text is content, as reading a checkout page is already not paying; the field's name, the page address and the button say what the action is, so those are what the rules read for a typed entry. A news wire (business, news or press wire) no longer counts as a wire of money anywhere else either.
…ment On the candidate shape the computer records (the typed text in args, the field and page in target): notes about purchase orders and payments, and a Business Wire source, are not handed off; a card number field, a checkout page and a new password field still are, whatever is typed. A link to a release on Business Wire is not a payment; "Wire the deposit", "Send a wire" and "Start a wire transfer" still are. The assertion-shape allow-list follows the existing entry the new tests moved down.
Before the browser runs a computer action, the server checks the call against the conversation's saved copy, waiting up to five seconds for it to appear. Intelligence saves a call's arguments delta by delta, behind the stream, and the wait stopped as soon as the call appeared: a read that found half the arguments refused the action ("That unanswered tool call is not saved in this conversation"), or threw when the half did not parse, which the route answers as "Supply a valid request". The check, lifted into savedToolCall, now waits until the saved call parses and matches, within the same five seconds, and still refuses one that never does.
The saved copy is read as Intelligence returned it part-way through saving a click: half the JSON, then all of it but the last key, then whole. The call is matched rather than refused. A call that never appears, never matches, or never finishes saving is still refused once the wait runs out, and one that already has a result is reported as answered.
… not refused while it saves
davidmckayv
requested review from
MikeRyanDev,
guidovizoso,
mxmzb and
tylerslaton
as code owners
October 25, 2026 22:15
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.
Two bugs that stopped a Bot filling in a form in its browser. Both showed up running a Bot through a CRM's New account form end to end; each fix has a regression test that fails on
mainand passes here.Filling in a form was mistaken for paying.
safetyRequirementread acomputer_typecall's typed text along with its target, so the payments rule matched words in the content. A note about a customer's "purchase orders", or a source field reading "Business Wire", was handed back to the person with "Paying, purchasing or moving money is always done by the person", mid-form. Typed text is content, the way reading a checkout page is already not paying: for a typed entry the rules now read the field's name, the page address and the button, not the words typed. A "Card number" field, a checkout page and a "New password" field still go to the person whatever is typed. Separately, a news wire (business, news or press wire) on a link or button no longer counts as wiring money; "Wire the deposit", "Send a wire" and "wire transfer" still do.A browser step was refused while it was being saved. Before the browser runs a computer action, the server checks the call against the conversation's saved copy, waiting up to five seconds for it to appear. Intelligence saves a call's arguments delta by delta, behind the stream, and the wait stopped as soon as the call appeared, so a read that found half the arguments refused the step ("That unanswered tool call is not saved in this conversation"), or threw when the half did not parse, which the route answers as "Supply a valid request". The Bot then stopped partway or asked for its approval a second time. The check, lifted into
savedToolCall, now waits until the saved call parses and matches, within the same five seconds, and still refuses one that never does.Tests
approvals-policy.test.ts: typing judged by its field and page, on the candidate shape the computer records; a news wire is not a payment, wiring money still is. Theassertion-shapeallow-list follows the existing entry the new tests moved down.approvals-saved-call.test.ts(new): the saved copy read half saved, then whole, is matched; a call that never appears, never matches or never finishes saving is refused; one with a result is reported as answered. Against the old logic the first case throwsJSON Parse error, the route's "Supply a valid request".Verified in a real browser: with both fixes a Bot created five CRM accounts (every field, Notes and Source included) without a hand-off or a refused step, across repeated runs.