feat: expose download and waitForDownload actions in browser agent tool#12378
feat: expose download and waitForDownload actions in browser agent tool#12378vabole wants to merge 1 commit into
Conversation
| const browserActionMocks = vi.hoisted(() => ({ | ||
| browserDownload: vi.fn(async () => ({ | ||
| ok: true, | ||
| targetId: "t1", |
There was a problem hiding this comment.
Mock ordering breaks tests
browserActionMocks/vi.mock("../../browser/client-actions.js", ...) is declared after other vi.mock(...) calls. With Vitest hoisting semantics, mock factory evaluation can occur before browserActionMocks is initialized, which can make the mock return undefined functions or throw at import time depending on module load order. This file previously avoided that by not referencing late-declared variables in mock factories.
Move the browserActionMocks = vi.hoisted(...) block above any vi.mock that uses it (or inline the hoisted mocks inside the vi.mock factory) so the mocked exports are always defined when the module is evaluated.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/tools/browser-tool.test.ts
Line: 71:74
Comment:
**Mock ordering breaks tests**
`browserActionMocks`/`vi.mock("../../browser/client-actions.js", ...)` is declared *after* other `vi.mock(...)` calls. With Vitest hoisting semantics, mock factory evaluation can occur before `browserActionMocks` is initialized, which can make the mock return `undefined` functions or throw at import time depending on module load order. This file previously avoided that by not referencing late-declared variables in mock factories.
Move the `browserActionMocks = vi.hoisted(...)` block above any `vi.mock` that uses it (or inline the hoisted mocks inside the `vi.mock` factory) so the mocked exports are always defined when the module is evaluated.
How can I resolve this? If you propose a fix, please make it concise.There was a problem hiding this comment.
This is a false positive — vi.hoisted() specifically hoists the variable initialization to the top of the file before any vi.mock() factories execute. That's its entire purpose (Vitest docs). The ordering in source code is irrelevant since all vi.hoisted() calls run before module evaluation.
All 14 tests pass consistently, confirming no initialization issue.
bfc1ccb to
f92900f
Compare
|
This pull request has been automatically marked as stale due to inactivity. |
The browser download functionality was fully implemented at the Playwright
layer (pw-tools-core.downloads.ts) and CLI layer (register.files-downloads.ts)
but was missing from the agent tool — the interface AI agents actually use.
Changes:
- Add 'download' action: clicks a ref and saves the resulting download
- Add 'waitForDownload' action: waits for the next download without clicking
- Both return { path, url, suggestedFilename } metadata
- Add 'path' parameter to browser tool schema for save location
- Support proxied (node) and local execution paths
- Add unit tests for both actions
This closes the gap where agents had to use XHR/fetch workarounds to
intercept file downloads from websites.
|
This pull request has been automatically marked as stale due to inactivity. |
Summary
The browser download functionality was fully implemented at the Playwright layer (
pw-tools-core.downloads.ts) and CLI layer (register.files-downloads.ts) but was missing from the agent tool — the interface AI agents actually use via thebrowsertool.This meant agents had no way to download files from websites, forcing workarounds like XHR/fetch interception with localStorage to capture downloads.
Changes
New actions in browser agent tool
download— Click a ref and save the resulting download:{ "action": "download", "ref": "e12", "path": "/tmp/report.pdf" }waitForDownload— Wait for the next download (no click):{ "action": "waitForDownload", "path": "/tmp/export.csv", "timeoutMs": 30000 }Both return:
{ "ok": true, "targetId": "...", "download": { "path": "/tmp/report.pdf", "url": "https://example.com/report.pdf", "suggestedFilename": "report.pdf" } }Files changed
browser-tool.tsdownloadandwaitForDownloadcase handlers following the existingupload/dialogpatternbrowser-tool.schema.tsBROWSER_TOOL_ACTIONS, addedpathparameterbrowser-tool.test.tsDesign decisions
upload/dialogwiring — sameproxyRequestpath for node targets, samejsonResultwrapping, same parameter extraction stylepathis required fordownload(you must specify where to save), optional forwaitForDownload(defaults to temp directory)pathadded as schema-level optional parameter: Runtime enforcement handles required vs optional per actionTesting
Agent prompt used
This was implemented by Codex (gpt-5.3-codex, full-auto mode) with the following prompt:
Click to expand prompt
Greptile Overview
Greptile Summary
This PR wires existing Playwright/CLI download support into the agent-facing
browsertool by adding two new actions:download(click by ref and save to a specified path) andwaitForDownload(wait for the next download, optionally specifying a save path). It updates the browser tool schema to accept the new actions and apathfield, and adds unit coverage that mocks the underlyingbrowserDownload/browserWaitForDownloadclient-actions and asserts the tool passes throughref,path,targetId,timeoutMs, andprofile.The change fits into the existing browser tool pattern by routing through the node browser proxy (
proxyRequest) when available (POST/downloadand/wait/download) and falling back to direct client-actions calls otherwise, returning results via the existingjsonResultwrapper.Confidence Score: 4/5
vi.mock("../../browser/client-actions.js")factory referencingbrowserActionMocksdeclared later in the file, which can break depending on Vitest hoisting/evaluation order, leading to intermittent test/runtime failures.(2/5) Greptile learns from your feedback when you react with thumbs up/down!