Skip to content

fix(browser): notify agent when click triggers download#93307

Merged
steipete merged 11 commits into
openclaw:mainfrom
sunlit-deng:fix/issue-93250-Bug---No-notification-when-br
Jul 6, 2026
Merged

fix(browser): notify agent when click triggers download#93307
steipete merged 11 commits into
openclaw:mainfrom
sunlit-deng:fix/issue-93250-Bug---No-notification-when-br

Conversation

@sunlit-deng

@sunlit-deng sunlit-deng commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

When a browser /act action triggers a file download, OpenClaw already saves the unmanaged Playwright download, but the agent-visible /act response did not include the downloaded filename or saved path.

That meant an agent could successfully trigger a download, receive only a generic success response, and then retry because it had no completion/path feedback for the saved file.

Fixes #93250

Why This Change Was Made

This change adds action-scoped download capture around Playwright-backed /act execution and returns optional downloads metadata in the /act JSON response.

The response includes the saved path and suggested filename for downloads observed during click, coordinate click, batch, and evaluate actions. The downloads payload is page-level observation metadata for the action window, not an exclusive ownership claim: overlapping /act calls on the same page may receive the same saved download so the browser event is not silently dropped.

User Impact

Agents can now see that a browser-triggered download completed, including where the file was saved, and avoid retrying an action that already produced the expected file.

Existing /act responses remain compatible: the downloads field is optional and only appears when a download is captured.

Evidence

Live click-triggered /act proof on macOS, Node.js v26.0.0, Chrome 149.0.7827.197:

$ curl --noproxy '*' -s -o /dev/null -w "HTTP %{http_code}\n" http://127.0.0.1:53558/
HTTP 200

$ curl --noproxy '*' -s http://127.0.0.1:53559/json/version | node -e "..."
Chrome/149.0.7827.197

$ node click-act-proof.mts
POST /act { kind: 'click', selector: '#download' }

POST /act RESPONSE (agent-visible JSON)
{
  "downloads": {
    "count": 1,
    "recent": [
      {
        "suggestedFilename": "act-click-proof-download.txt",
        "savedPath": "/tmp/openclaw/downloads/8a8d3c2f-3b69-4b8f-aa74-ad75f8d441e3-act-click-proof-download.txt"
      }
    ]
  }
}

$ node -e "const fs=require('fs'); const p='/tmp/openclaw/downloads/8a8d3c2f-3b69-4b8f-aa74-ad75f8d441e3-act-click-proof-download.txt'; console.log('exists:', fs.existsSync(p), 'content:', fs.readFileSync(p, 'utf8').trim())"
exists: true content: OpenClaw /act click download proof - PR 93307

Focused tests:

$ node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-browser.config.ts browser/src/browser/pw-session.test.ts

 Test Files  1 passed (1)
      Tests  21 passed (21)

Includes overlap contract coverage: broadcasts downloads to all active captures to prevent misattribution.

$ node scripts/run-vitest.mjs run --config test/vitest/vitest.extension-browser.config.ts browser/src/browser/server.agent-contract-core.test.ts

 Test Files  1 passed (1)
      Tests  20 passed (20)

AI-assisted: built with Codex

@openclaw-barnacle openclaw-barnacle Bot added size: S proof: supplied External PR includes structured after-fix real behavior proof. labels Jun 15, 2026
@clawsweeper

clawsweeper Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 5, 2026, 10:40 PM ET / 02:40 UTC.

Summary
The PR adds action-scoped Playwright download capture for browser /act, returns optional downloads metadata in /act responses, updates the typed client/docs, and adds browser regression coverage.

PR surface: Source +200, Tests +467, Docs +1. Total +668 across 10 files.

Reproducibility: yes. at source level: current main auto-saves unmanaged Playwright downloads but /act click-style responses return no download metadata. I did not run a live browser repro in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Agent response contract: 1 optional /act field added. The new downloads payload is agent-visible API surface, so route shape, typed client shape, docs, and live proof need to match before merge.
  • Action capture drain window: 1,000 ms max drain; 250 ms quiet window. The patch intentionally waits for download events after Playwright-backed actions, which affects no-download action latency and overlap semantics.

Stored data model
Persistent data-model change detected: serialized state: extensions/browser/src/browser/pw-session.test.ts, vector/embedding metadata: docs/tools/browser.md, vector/embedding metadata: extensions/browser/src/browser/pw-session.test.ts, vector/embedding metadata: extensions/browser/src/browser/server.agent-contract-core.test.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #93250
Summary: This PR is an implementation candidate for the canonical browser click-download feedback issue; several closed PRs attempted similar fixes and one open PR remains an alternate explicit-action direction.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🐚 platinum hermit
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Update the PR body with a current-head live /act click proof showing downloads: [{ url, suggestedFilename, path }] and the saved file content or existence check.
  • Have a maintainer explicitly accept the implicit /act metadata and latest-action overlap semantics, or request the alternate API shape.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body contains live terminal proof, but it demonstrates the older { count, recent } response object while current head returns a downloads array; refresh the PR body with current-head live output and redact private paths, IPs, tokens, phone numbers, and endpoints. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The current-head response shape changed to a downloads array after the live proof was captured, so the proof no longer demonstrates the exact behavior a user would receive from this head.
  • [P1] Same-page overlapping /act calls use latest-action page ownership, which can associate a download with a different overlapping action unless maintainers accept that observation contract.
  • [P1] The open explicit-action PR at feat(browser): add agent download actions #74411 solves the same user problem with download and waitfordownload actions, so maintainers should choose one final browser download API shape.
  • [P1] No-download actions can now spend a bounded drain window looking for action downloads, which is intentional latency that should stay visible before merge.

Maintainer options:

  1. Accept current observation contract (recommended)
    Maintainers can accept that latest-action page ownership is the intended overlap behavior once current-head proof shows the downloads array response.
  2. Tighten overlap ownership
    Require a code change and focused regression so an unrelated overlapping action cannot receive the triggering action's download metadata.
  3. Choose explicit download actions
    Pause this PR if maintainers want the explicit download and waitfordownload action surface to be the canonical fix.

Next step before merge

  • [P1] The next action is maintainer API/semantics judgment plus a current-head proof refresh, not a narrow automated repair.

Maintainer decision needed

  • Question: Should OpenClaw solve browser click-download feedback by returning optional downloads metadata from /act with latest-action page ownership, or require explicit download actions or stricter ownership before merge?
  • Rationale: The code path is plausible and well-covered, but it changes the agent-visible browser API while an explicit-action alternative remains open and the current proof predates the array response shape.
  • Likely owner: steipete — He has the strongest current history and already revised this PR branch's browser download implementation.
  • Options:
    • Land implicit /act metadata (recommended): Accept the current optional downloads array contract and latest-action ownership semantics after the PR body is refreshed with current-head live proof.
    • Require stricter ownership: Ask for semantics that avoid assigning a download to an unrelated overlapping action before merge.
    • Prefer explicit actions: Pause or close this PR in favor of an explicit download and waitfordownload browser tool API.

Security
Cleared: No concrete security or supply-chain regression was found; the patch reuses existing managed download saving and adds URL policy validation before action-owned saves.

Review details

Best possible solution:

Land this PR or a narrow replacement after updated current-head proof shows the array response and maintainers accept the implicit /act metadata and same-page ownership contract, then close the canonical issue and supersede the duplicate candidates.

Do we have a high-confidence way to reproduce the issue?

Yes, at source level: current main auto-saves unmanaged Playwright downloads but /act click-style responses return no download metadata. I did not run a live browser repro in this read-only review.

Is this the best way to solve the issue?

Unclear as a final product shape: optional /act download metadata is a maintainable low-friction fix, but maintainers still need to accept it over explicit download actions and confirm the overlap ownership contract.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 7b9df9e18765.

Label changes

Label changes:

  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body contains live terminal proof, but it demonstrates the older { count, recent } response object while current head returns a downloads array; refresh the PR body with current-head live output and redact private paths, IPs, tokens, phone numbers, and endpoints. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • remove proof: sufficient: Current real behavior proof status is insufficient, not sufficient.
  • remove status: 👀 ready for maintainer look: Current PR status label is status: 📣 needs proof.

Label justifications:

  • P2: This is a bounded browser automation reliability bug that can cause wasteful agent retries but does not block the core runtime or create an emergency.
  • merge-risk: 🚨 session-state: The PR adds per-page action download capture state that can associate download metadata with overlapping action responses on the same page.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🐚 platinum hermit.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body contains live terminal proof, but it demonstrates the older { count, recent } response object while current head returns a downloads array; refresh the PR body with current-head live output and redact private paths, IPs, tokens, phone numbers, and endpoints. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +200, Tests +467, Docs +1. Total +668 across 10 files.

View PR surface stats
Area Files Added Removed Net
Source 5 216 16 +200
Tests 4 467 0 +467
Docs 1 1 0 +1
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 10 684 16 +668

What I checked:

Likely related people:

  • steipete: Peter Steinberger authored the bundled browser plugin ownership refactor, merged the recent browser download completion PR, and also authored the latest commits on this PR branch. (role: recent area contributor and likely follow-up owner; confidence: high; commits: 8eeb7f082975, 733ea48a324b, 6eacdd451e06; files: extensions/browser/src/browser/routes/agent.act.ts, extensions/browser/src/browser/pw-session.ts, extensions/browser/src/browser/pw-tools-core.interactions.ts)
  • zhangguiping-xydt: The merged browser CDP download completion PR authored by this contributor introduced the current unmanaged-download auto-save behavior that this PR builds on. (role: recent download behavior contributor; confidence: medium; commits: 7a49b160a4e5; files: extensions/browser/src/browser/pw-session.ts, extensions/browser/src/browser/pw-download-capture.ts)
  • joshavant: Josh Avant authored the /act route action execution and contract consolidation that defines the response path this PR extends. (role: adjacent contract contributor; confidence: medium; commits: f096fc440686; files: extensions/browser/src/browser/routes/agent.act.ts, extensions/browser/src/browser/pw-tools-core.interactions.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-07-02T14:46:52.471Z sha aa5c3d5 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 15, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jun 16, 2026
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. label Jun 19, 2026
@sunlit-deng
sunlit-deng force-pushed the fix/issue-93250-Bug---No-notification-when-br branch from 31a2a96 to d920f31 Compare June 24, 2026 02:17
@openclaw-barnacle openclaw-barnacle Bot added the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 24, 2026
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@openclaw-barnacle openclaw-barnacle Bot removed the triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. label Jun 24, 2026
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

1 similar comment
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

sunlit-deng added a commit to sunlit-deng/openclaw that referenced this pull request Jun 24, 2026
Fixes eslint(curly) failures in drainPendingDownloadSaves and
pickNewDownloads. PR openclaw#93307 required CI gate.

Ref: ClawSweeper P1 review finding
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

1 similar comment
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@sunlit-deng
sunlit-deng force-pushed the fix/issue-93250-Bug---No-notification-when-br branch from 89b1705 to 57eb990 Compare June 25, 2026 02:56
sunlit-deng added a commit to sunlit-deng/openclaw that referenced this pull request Jun 25, 2026
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

1 similar comment
@sunlit-deng

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@steipete
steipete force-pushed the fix/issue-93250-Bug---No-notification-when-br branch from aa5c3d5 to 5f08d18 Compare July 6, 2026 02:20
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation size: L and removed size: M labels Jul 6, 2026
@steipete
steipete force-pushed the fix/issue-93250-Bug---No-notification-when-br branch from 5f08d18 to 6eacdd4 Compare July 6, 2026 02:27
steipete pushed a commit to sunlit-deng/openclaw that referenced this pull request Jul 6, 2026
Fixes eslint(curly) failures in drainPendingDownloadSaves and
pickNewDownloads. PR openclaw#93307 required CI gate.

Ref: ClawSweeper P1 review finding
@clawsweeper clawsweeper Bot added status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 6, 2026
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Land-ready proof for exact head 1a1564c955155b9fc0f6f4de47ec18b249969576.

What changed from the contributor branch:

  • Reused the shared managed download contract from fix(browser): downloads complete over CDP connections #89416: { url, suggestedFilename, path }.
  • Removed the duplicate action saver, broadcast attribution, and unconditional 500 ms wait.
  • Added one bounded action owner covering click, Enter/key, form/select, evaluate, batch, and other DOM actions. Explicit wait/download ownership still wins.
  • Collected sibling download events through a bounded quiet window; detached ownership before slow file I/O; validated every action download URL before aggregating saves.
  • On policy denial, quarantined the target without closing the user-owned tab.

Verification:

  • Fresh autoreview: clean after fixing action-kind, sibling-event, slow-save, fail-fast policy, and detachment races.
  • Sanitized AWS Crabbox: provider aws, lease cbx_55f3592fb456, public network, no Tailscale, empty instance profile, no hydration. Exact-head run run_0cc05052b9cc passed 4 focused files / 90 tests, then pnpm check:changed passed production/test typechecks, extension lint, and selected guards.
  • macOS exact-head pnpm build: passed.
  • Hosted exact-head checks: required contexts green; PR merge state CLEAN.

Real Gateway + browser-agent proof on predecessor 6eacdd451e0694f766cb1d92551b8ae475c54a90; the Browser/docs trees are byte-identical after the main-only rebase to this exact head:

  • Started the built Dev Gateway at this SHA with an approved OpenAI service key and model openai/gpt-5.5; only the Browser tool was allowed.
  • Click run d8730232-4abb-4b72-8c3e-7b80e06e28ee: 3 Browser calls, 0 failures. The click result returned the exact URL, filename pr93307-click-click-a7c91.txt, and managed path. Independent check: mode 0600, expected 26-byte nonce content, SHA-256 d6163eeec7426cbde342efce1dfd5facf4a9db9a1297e655497d88441ed65fdd.
  • Enter run 32ade9fc-b7bb-4fc8-aad1-3577a872843e: 6 Browser calls, 0 failures. The Enter key action returned the distinct URL, filename pr93307-enter-enter-b4e28.txt, and managed path. Independent check: mode 0600, expected distinct 26-byte content, SHA-256 564da315242ff7faf6f2f817ca339010f49ae5573df68937bc4adf2e00ad83b2.
  • Strict-policy run 63d34127-4428-42fe-bb41-f7dfe460b47e: an allowed localhost page redirected the download to blocked 127.0.0.1; the Browser reported browser navigation blocked by policy. Downloads stayed exactly count 93, digest 9553a8e6db9d0217f1f56207990cf119f740730717be0c3ca3f18d6f1de2eacf, with no blocked artifact.
  • After denial, Gateway health remained live and raw Chrome target FEDB99B791D3803709628B0A84DC600D remained open on the original strict page. The security boundary failed closed without destroying user functionality.

This is the best fix for #93250: one managed save owner, one response type, pre-write policy validation, and real agent-visible completion evidence.

sunlit-deng and others added 11 commits July 5, 2026 22:51
…esponse

- Add drainPendingDownloadSaves() to wait for in-flight saveAs before sampling
- Use monotonic downloadSeq cursor instead of bounded-list length
- Propagate downloads info in POST /act response for click/batch/evaluate

Fixes openclaw#93250
Fixes eslint(curly) failures in drainPendingDownloadSaves and
pickNewDownloads. PR openclaw#93307 required CI gate.

Ref: ClawSweeper P1 review finding
…isattribution

When concurrent /act calls overlap on the same page, using
state.actionDownloadCaptures.at(-1) assigned downloads to the wrong
action's capture. Push managed save promises to all active captures
so the triggering action always receives its download metadata.

Also adds regression tests: broadcast-to-all-captures, sequential
capture isolation, and strengthen the dispose test to assert no
re-capture after disposal.
…n throws before drain

Move managedSave.catch() before the captures-branch check so the
rejection handler always runs, preventing an unhandled promise
rejection when the action throws before drain() is called. Simplify
the handler by removing the now-dead return + catch at the bottom.
- Add optional downloads field to BrowserActResponse type contract so
  typed callers of browserAct() can consume the new payload without casts.
- Remove unused afterDispose variable in pw-session tests (lint fix).
capture.promises is not cleared by dispose(), so re-draining a disposed
capture still returns pre-dispose results. This is benign — callers
should drain before disposing. Update the test to assert the actual
behavior (still shows old results, new download not captured).
@steipete
steipete force-pushed the fix/issue-93250-Bug---No-notification-when-br branch from 6eacdd4 to 1a1564c Compare July 6, 2026 02:51
@steipete
steipete merged commit ae53570 into openclaw:main Jul 6, 2026
88 checks passed
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 6, 2026
* fix(browser): drain download saves and use monotonic cursor for act response

- Add drainPendingDownloadSaves() to wait for in-flight saveAs before sampling
- Use monotonic downloadSeq cursor instead of bounded-list length
- Propagate downloads info in POST /act response for click/batch/evaluate

Fixes openclaw#93250

* fix(lint): add braces around single-line if returns

Fixes eslint(curly) failures in drainPendingDownloadSaves and
pickNewDownloads. PR openclaw#93307 required CI gate.

Ref: ClawSweeper P1 review finding

* fix(browser): scope act download metadata to action

* fix(browser): broadcast downloads to all active captures to prevent misattribution

When concurrent /act calls overlap on the same page, using
state.actionDownloadCaptures.at(-1) assigned downloads to the wrong
action's capture. Push managed save promises to all active captures
so the triggering action always receives its download metadata.

Also adds regression tests: broadcast-to-all-captures, sequential
capture isolation, and strengthen the dispose test to assert no
re-capture after disposal.

* fix(browser): prevent unhandled rejection when download capture action throws before drain

Move managedSave.catch() before the captures-branch check so the
rejection handler always runs, preventing an unhandled promise
rejection when the action throws before drain() is called. Simplify
the handler by removing the now-dead return + catch at the bottom.

* fix(browser): type downloads in BrowserActResponse, fix lint unused var

- Add optional downloads field to BrowserActResponse type contract so
  typed callers of browserAct() can consume the new payload without casts.
- Remove unused afterDispose variable in pw-session tests (lint fix).

* fix(test): correct post-dispose download assertion

capture.promises is not cleared by dispose(), so re-draining a disposed
capture still returns pre-dispose results. This is benign — callers
should drain before disposing. Update the test to assert the actual
behavior (still shows old results, new download not captured).

* test(browser): cover /act download metadata response

* refactor(browser): report action-owned downloads safely

* fix(browser): close action download ownership races

* test(browser): type action download capture mock

---------

Co-authored-by: Peter Steinberger <[email protected]>
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
* fix(browser): drain download saves and use monotonic cursor for act response

- Add drainPendingDownloadSaves() to wait for in-flight saveAs before sampling
- Use monotonic downloadSeq cursor instead of bounded-list length
- Propagate downloads info in POST /act response for click/batch/evaluate

Fixes openclaw#93250

* fix(lint): add braces around single-line if returns

Fixes eslint(curly) failures in drainPendingDownloadSaves and
pickNewDownloads. PR openclaw#93307 required CI gate.

Ref: ClawSweeper P1 review finding

* fix(browser): scope act download metadata to action

* fix(browser): broadcast downloads to all active captures to prevent misattribution

When concurrent /act calls overlap on the same page, using
state.actionDownloadCaptures.at(-1) assigned downloads to the wrong
action's capture. Push managed save promises to all active captures
so the triggering action always receives its download metadata.

Also adds regression tests: broadcast-to-all-captures, sequential
capture isolation, and strengthen the dispose test to assert no
re-capture after disposal.

* fix(browser): prevent unhandled rejection when download capture action throws before drain

Move managedSave.catch() before the captures-branch check so the
rejection handler always runs, preventing an unhandled promise
rejection when the action throws before drain() is called. Simplify
the handler by removing the now-dead return + catch at the bottom.

* fix(browser): type downloads in BrowserActResponse, fix lint unused var

- Add optional downloads field to BrowserActResponse type contract so
  typed callers of browserAct() can consume the new payload without casts.
- Remove unused afterDispose variable in pw-session tests (lint fix).

* fix(test): correct post-dispose download assertion

capture.promises is not cleared by dispose(), so re-draining a disposed
capture still returns pre-dispose results. This is benign — callers
should drain before disposing. Update the test to assert the actual
behavior (still shows old results, new download not captured).

* test(browser): cover /act download metadata response

* refactor(browser): report action-owned downloads safely

* fix(browser): close action download ownership races

* test(browser): type action download capture mock

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Improvements or additions to documentation merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: L status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: No notification when browser click triggers a download – agent keeps retrying

2 participants