execute_playwright_code: drop replays + browser lifecycle; add manage_replays tool#124
execute_playwright_code: drop replays + browser lifecycle; add manage_replays tool#124dprevoznik wants to merge 7 commits into
Conversation
Each execute_playwright_code call wrapped the run in replays.start / replays.stop and validated existing sessions with a browsers.retrieve, adding three round trips around the one useful call. In a tight agent loop that latency lands on the critical path every turn. Drop the replay start/stop and the pre-execute retrieve; execute surfaces a not-found error on its own. Existing-session calls now make a single round trip. Video replay is handled separately via managed replay controls. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Fold browser lifecycle out of the execute tool: session_id is now required, and the tool no longer creates a stealth browser when it is omitted or deletes the browser afterward. It is now a thin passthrough to browsers.playwright.execute -- inputs in, outputs back. Creating and deleting a browser inside an "execute" call hid a lifecycle (and a baked-in stealth default) the caller never chose, and put create/ delete round trips on the path. Session lifecycle belongs to manage_browsers; recording belongs to managed replays. BREAKING CHANGE: callers that relied on omitting session_id to get a one-shot auto-created browser must now create a session with manage_browsers first and pass its session_id. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce a dedicated replays toolset backing browsers.replays with start/stop/list actions, registered as the "replays" toolset (gated by KERNEL_MCP_DISABLED_TOOLSETS like the others). Recording is now session-scoped and opt-in: start once, run the automation, then stop -- replacing the per-call recording that used to be wrapped around every execute_playwright_code call. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Let the agent choose between page.screenshot() and computer_action rather than steering it toward one. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ef5c3dc to
8b3e732
Compare
8b3e732 to
1265a2d
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1265a2d. Configure here.
| ); | ||
| return itemsJsonResponse(replays, { | ||
| emptyText: "No replays found for this session", | ||
| }); |
There was a problem hiding this comment.
List skips pagination contract
Medium Severity
manage_replays list calls browsers.replays.list with only session_id and returns via itemsJsonResponse, without paginationParams or paginatedJsonResponse. Other MCP tool list actions expose limit/offset and return { items, has_more, next_offset }, so this path breaks the shared list contract agents rely on.
Triggered by learned rule: MCP resources iterate all pages; tool list actions return single pages
Reviewed by Cursor Bugbot for commit 1265a2d. Configure here.
There was a problem hiding this comment.
Not applicable here — the SDK's browsers.replays.list(id) returns a plain Array (ReplayListResponse), not a paginated page. There's no limit/offset/cursor to honor (unlike extensions.list/proxies.list, which return a page object), so it returns every replay for the session in one call. itemsJsonResponse still emits the shared { items, has_more, next_offset } envelope, so agents get the same shape. Adding paginationParams would advertise pagination the endpoint doesn't support. Leaving as-is.
dprevoznik
left a comment
There was a problem hiding this comment.
Reviewed mcp changes locally and breaking decision to simplify playwright execution tool.


Summary
Splits browser lifecycle and replay recording out of
execute_playwright_codeand gives replays a dedicated tool. Net effect: the execute path is a lean passthrough, and recording becomes opt-in and session-scoped.1. Remove per-call replay recording from
execute_playwright_codeEvery call wrapped the run in
replays.start/replays.stopand validated existing sessions withbrowsers.retrieve, so an existing-session call made four sequential round trips —retrieve→replays.start→execute→replays.stop— when onlyexecuteis useful work. The replay start/stop fired unconditionally whether or not the caller brought their own session, so this tax was on the critical path of every call in a tight agent loop.Removed the replay start/stop (success and error paths), dropped
replay_urlfrom the response, and dropped the pre-executebrowsers.retrievevalidation (executesurfaces a not-found error on its own).2. Make
execute_playwright_codea passthrough — no browser lifecyclesession_idis now required. The tool no longer creates a stealth browser whensession_idis omitted, and no longer deletes the browser afterward. It's now a thin wrapper overbrowsers.playwright.execute— inputs in, outputs back. Session lifecycle belongs tomanage_browsers.3. Add
manage_replaystoolNew
replaystoolset (src/lib/mcp/tools/replays.ts), backingbrowsers.replayswithstart/stop/listactions, gated byKERNEL_MCP_DISABLED_TOOLSETSlike the rest. This restores the replay capability removed in (1), but session-scoped and opt-in: start once, run the automation, then stop — instead of recording each call separately.starttakes optionalframerate,max_duration_in_seconds, andrecord_audio.Callers that relied on omitting
session_idto get a one-shot, auto-created-and-deleted browser must now:manage_browsers(actioncreate),session_idtoexecute_playwright_code, andmanage_browserswhen done.Callers wanting a video replay must now
manage_replaysstart/stop around their calls instead of readingreplay_urloff each response. Existing callers that already pass asession_idand don't use the replay URL are otherwise unaffected.Follow-ups (not in this PR)
computer_actionlatency/defaults tweaks (reword away from batch-by-default, viewport-default screenshots).execute_playwright_codea fuller description again — it's now a short one-liner, and more usage guidance could help agents use it correctly.Testing
tsc --noEmitandprettier --checkpass.Confirmed:
manage_replaysis registered;execute_playwright_coderequiressession_idand returns noreplay_url; a browser is not deleted after execute (lifecycle removed); omittingsession_idis rejected; andmanage_replaysstart/stop/list all work.Two gotchas when running the Inspector: use
127.0.0.1(notlocalhost, which its Node fetch resolves to IPv6 and fails), and pass--transport streamable-http. No.env/Clerk/Redis is needed — the API-key bearer path skips them, sobun run devboots clean.Note
Medium Risk
Breaking change for agents that omitted
session_idor depended on automaticreplay_url; behavior change on a high-traffic automation path but logic is simpler and delegated to existing SDK APIs.Overview
Breaking MCP contract change:
execute_playwright_codeis now a thin wrapper aroundbrowsers.playwright.execute—session_idis required, with no implicit browser create/delete and no per-call replay recording. Responses no longer includereplay_url, and the extraretrieve/replays.start/replays.stopround trips on each call are removed.New opt-in replay surface: Registers a
replaystoolset andmanage_replays(start/stop/liston a session, optional framerate, duration, and audio on start), gated like other toolsets viaKERNEL_MCP_DISABLED_TOOLSETS(documented in.env.example).Docs: README and AGENTS.md describe the new workflow (create session → execute → optional
manage_replays; MCP Inspector testing notes).Reviewed by Cursor Bugbot for commit 8b3e732. Bugbot is set up for automated code reviews on this repo. Configure here.