You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(browser): retain post-action refs for chained actions (#252)
## Summary
- Bind the fresh accessibility tree and XPath map after every successful
deterministic browser action.
- Allow required multi-step checks to chain directly from post-action
refs without another observation.
- Remove unused Stagehand action payloads and clear bound refs whenever
the browser runtime is discarded.
## Root Cause
The driver returned a post-action tree but cleared its server-held ref
map. A subsequent action selected a ref from that returned tree and
received a stale-state rejection, leading the agent to observe or reopen
the page repeatedly.
## Architecture
`browser_observe` and successful `browser_act` now produce the same
complete state boundary: bounded tree for the model plus the matching
XPath map retained only inside the sandbox driver. Consuming a ref
invalidates its prior boundary; success atomically replaces it with the
post-action boundary.
## Decisions Made
| Decision | Choice | Alternative | Reasoning |
|---|---|---|---|
| Multi-step state | Bind post-action tree and map atomically | Require
observe after every action | Makes the returned tree truthful and
removes redundant inference/round trips. |
| Action output | Return action identity and bounded state only | Echo
Stagehand result | The raw result is unused and adds token/serialization
cost. |
| Runtime discard | Clear bound observation | Preserve it | Refs cannot
outlive the Chromium runtime that created them. |
## Production Reproduction
- Ordinary prompt: build a grocery list and verify add, complete, and
delete.
- Fresh production run entered Working quickly, then repeated
observe/act/open for more than six minutes because chained refs were
rejected.
- Reproduction chat:
https://trycheatcode.com/chats/019ff5c6-a3c7-7e77-a513-176a478282b3
## Verification
- [x] `pnpm lint`
- [x] `pnpm typecheck`
- [x] `pnpm turbo build --force`
- [x] `pnpm deadcode`
- [x] `pnpm architecture:check`
- [x] `pnpm turbo skills:build`
- [x] `node --check infra/containers/sandbox/browser-driver/server.js`
- [ ] Build, scan, publish, and promote a new immutable Daytona snapshot
- [ ] Repeat ordinary-user web and mobile flows on production
## Related
- Deterministic browser tooling: #250
- Previous snapshot promotion: #251
Copy file name to clipboardExpand all lines: packages/agent-core/src/mastra/system-prompt.ts
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -206,7 +206,7 @@ Beyond these you also have browser, document-generation, data-analysis, web-rese
206
206
constWEB_MODULE=`## Building web apps
207
207
208
208
Make the app real and complete: working features, real data flow, considered design. Default to a clean modern stack — React / Next.js. Ship something polished: sensible colour and type, responsive, mobile-first, no lorem ipsum, no dead buttons, no placeholder images. Write the files, add or update dependencies only when the app actually needs them, and start the dev server early with code_start_dev_server (request port 5173) so you're always working against the running app. The managed server restores an unchanged project's existing dependencies itself. Never substitute a shell process for the managed preview, even for a static server or when restarting an existing project.
209
-
Verify it in the browser: open the app's INTERNAL address in the sandbox's headed Chromium — http://localhost:<port> (e.g. http://localhost:5173), NOT the external preview link (your sandbox browser can't reach that). Take one screenshot with the exact visual acceptance criterion; its result includes a visual PASS/FAIL assessment, so do not take another screenshot unless you changed the rendered output. To exercise one representative interaction, call browser_observe once, choose one exact hyphenated element ref from its accessibility tree, and call browser_act with that ref plus the required method/value. browser_act returns the post-action page tree, so use that result to verify the interaction without another observation or extraction. Never invent a ref or selector, write a separate Playwright/Python test, or install another browser. If either check fails, fix the concrete defect and repeat only that changed check once; never loop on equivalent screenshots or interactions. If the browser can't load it at all, note you couldn't visually verify and go straight to your closing summary. The running app is shown to the user automatically in the Computer panel's Browser tab — never paste the preview URL.`;
209
+
Verify it in the browser: open the app's INTERNAL address in the sandbox's headed Chromium — http://localhost:<port> (e.g. http://localhost:5173), NOT the external preview link (your sandbox browser can't reach that). Take one screenshot with the exact visual acceptance criterion; its result includes a visual PASS/FAIL assessment, so do not take another screenshot unless you changed the rendered output. To exercise one representative interaction, call browser_observe once, choose one exact hyphenated element ref from its accessibility tree, and call browser_act with that ref plus the required method/value. browser_act returns an actionable post-action page tree, so use that result to verify the interaction without another observation or extraction. If the request explicitly requires another interaction, chain it from a fresh ref in that returned tree; observe again only after navigation, an external page change, or when the returned tree lacks the required element. Never invent a ref or selector, write a separate Playwright/Python test, or install another browser. If either check fails, fix the concrete defect and repeat only that changed check once; never loop on equivalent screenshots or interactions. If the browser can't load it at all, note you couldn't visually verify and go straight to your closing summary. The running app is shown to the user automatically in the Computer panel's Browser tab — never paste the preview URL.`;
210
210
211
211
constMOBILE_MODULE=`## Building the mobile app
212
212
@@ -219,7 +219,7 @@ Build the Expo Router screens for a polished, native-feeling app: real screens,
219
219
// keeps WEB_MODULE's "start the dev server yourself" guidance; this note only applies here.
220
220
constAPP_BUILDER_PREVIEW_NOTE=`## Your preview is already running — do not start your own
221
221
222
-
This project is scaffolded at the workspace root and its dev server + live preview are ALREADY running and managed for you before your turn begins (for a mobile app that's Metro serving the app on web plus the Expo Go QR). Do NOT initialize, scaffold, or create another app or nested project. Do NOT start, restart, or reconfigure the server yourself — no code_start_dev_server, \`expo start\`, \`npm run dev\`/\`web\`, or \`npx expo …\`: a second server fights the managed one for the project's port and breaks the preview. Use pnpm, never npm/npx, only when dependency changes are necessary. Inspect and edit the existing root files; the preview hot-reloads on save. Verify by opening the running app in the sandbox's headed Chromium at its INTERNAL localhost address; it's shown to the user automatically in the Computer/App panel — never paste the preview URL. Metro may briefly show an empty document while rebuilding the first web bundle after edits: wait for page content once and reload at most once before treating it as a defect. Take one screenshot with the exact visual acceptance criterion and use its returned PASS/FAIL assessment; never judge screenshot byte size. Exercise one representative interaction by calling browser_observe once, choosing one exact hyphenated element ref from its accessibility tree, and calling browser_act with that ref plus the required method/value. Use browser_act's post-action tree as the result check; do not observe or extract again. Never invent a ref or selector, write a separate Playwright/Python test, or install another browser. If a check fails, fix the concrete defect and repeat only that changed check once. Once the requested content renders, that interaction passes, and no blocking browser error remains, finish.`;
222
+
This project is scaffolded at the workspace root and its dev server + live preview are ALREADY running and managed for you before your turn begins (for a mobile app that's Metro serving the app on web plus the Expo Go QR). Do NOT initialize, scaffold, or create another app or nested project. Do NOT start, restart, or reconfigure the server yourself — no code_start_dev_server, \`expo start\`, \`npm run dev\`/\`web\`, or \`npx expo …\`: a second server fights the managed one for the project's port and breaks the preview. Use pnpm, never npm/npx, only when dependency changes are necessary. Inspect and edit the existing root files; the preview hot-reloads on save. Verify by opening the running app in the sandbox's headed Chromium at its INTERNAL localhost address; it's shown to the user automatically in the Computer/App panel — never paste the preview URL. Metro may briefly show an empty document while rebuilding the first web bundle after edits: wait for page content once and reload at most once before treating it as a defect. Take one screenshot with the exact visual acceptance criterion and use its returned PASS/FAIL assessment; never judge screenshot byte size. Exercise one representative interaction by calling browser_observe once, choosing one exact hyphenated element ref from its accessibility tree, and calling browser_act with that ref plus the required method/value. Use browser_act's actionable post-action tree as the result check; do not observe or extract again. If the request explicitly requires another interaction, chain it from a fresh ref in the returned tree; observe again only after navigation, an external page change, or when that tree lacks the required element. Never invent a ref or selector, write a separate Playwright/Python test, or install another browser. If a check fails, fix the concrete defect and repeat only that changed check once. Once the requested content renders, that interaction passes, and no blocking browser error remains, finish.`;
"Execute one deterministic action against an exact element ref from the immediately preceding browser_observe tree. The ref is page-bound and single-use; the result includes the post-action page tree.",
31
+
"Execute one deterministic action against an exact element ref from the latest browser_observe or browser_act tree. The consumed ref is page-bound and single-use; the result includes an actionable post-action page tree for the next step.",
0 commit comments