Bug Description
A2UI content renders momentarily then disappears because the macOS app's auto-navigation logic reloads the WebView in a loop. There are two related bugs:
Bug 1: shouldAutoNavigateToA2UI() returns wrong value (critical)
File: apps/macos/Sources/OpenClaw/CanvasWindowController.swift, line ~369
In shouldAutoNavigateToA2UI(lastAutoTarget:), when currentTarget == lastAutoTarget (i.e., the WebView is already showing the A2UI URL), the method returns true — causing the page to reload even though it's already at the correct URL. This should return false.
func shouldAutoNavigateToA2UI(lastAutoTarget: String?) -> Bool {
let trimmed = (self.currentTarget ?? "").trimmingCharacters(in: .whitespacesAndNewlines)
if trimmed.isEmpty || trimmed == "/" { return true }
if let lastAuto = lastAutoTarget?.trimmingCharacters(in: .whitespacesAndNewlines),
!lastAuto.isEmpty,
trimmed == lastAuto
{
return true // BUG: should be `return false`
}
return false
}
This gets triggered from two paths:
- Gateway snapshot observer (
CanvasManager.startGatewayObserver) — every gateway snapshot push triggers handleGatewayPush → maybeAutoNavigateToA2UI → controller.load(target:), reloading the page
CanvasManager.eval() — calls self.show(sessionKey:, path: nil) before every eval, which triggers maybeAutoNavigateToA2UIAsync, causing another reload
The result is that any A2UI content rendered via applyMessages() is immediately wiped by the page reload.
Bug 2: Gateway serves .js files with wrong MIME type
The gateway's static file server uses detectMime() which relies on file content sniffing. For JavaScript files (including a2ui.bundle.js), this returns application/octet-stream instead of application/javascript. The browser then refuses to execute the script.
File: src/cli/gateway-cli.ts (or wherever the canvas static server constructs MIME types)
The fix is to check file extension before falling back to content-based detection:
.js → application/javascript; charset=utf-8
.css → text/css; charset=utf-8
.json/.map → application/json; charset=utf-8
Steps to Reproduce
- Start gateway with
canvasHost.enabled: true
- Connect macOS app as node
- Run
openclaw nodes canvas a2ui push --text "Hello" (or any A2UI JSONL)
- Observe: content flashes briefly then the canvas goes blank
Expected Behavior
A2UI content should render and persist on the canvas until explicitly replaced.
Environment
- OpenClaw CLI: v2026.1.29
- OpenClaw macOS app: v2026.2.19
- macOS: Darwin 24.3.0
Workaround
Bug 2 (MIME type) can be patched in the compiled gateway dist file by adding extension checks before detectMime(). Bug 1 (auto-navigation) requires rebuilding the macOS app from source — no runtime workaround found.
Bug Description
A2UI content renders momentarily then disappears because the macOS app's auto-navigation logic reloads the WebView in a loop. There are two related bugs:
Bug 1:
shouldAutoNavigateToA2UI()returns wrong value (critical)File:
apps/macos/Sources/OpenClaw/CanvasWindowController.swift, line ~369In
shouldAutoNavigateToA2UI(lastAutoTarget:), whencurrentTarget == lastAutoTarget(i.e., the WebView is already showing the A2UI URL), the method returnstrue— causing the page to reload even though it's already at the correct URL. This should returnfalse.This gets triggered from two paths:
CanvasManager.startGatewayObserver) — every gateway snapshot push triggershandleGatewayPush→maybeAutoNavigateToA2UI→controller.load(target:), reloading the pageCanvasManager.eval()— callsself.show(sessionKey:, path: nil)before every eval, which triggersmaybeAutoNavigateToA2UIAsync, causing another reloadThe result is that any A2UI content rendered via
applyMessages()is immediately wiped by the page reload.Bug 2: Gateway serves
.jsfiles with wrong MIME typeThe gateway's static file server uses
detectMime()which relies on file content sniffing. For JavaScript files (includinga2ui.bundle.js), this returnsapplication/octet-streaminstead ofapplication/javascript. The browser then refuses to execute the script.File:
src/cli/gateway-cli.ts(or wherever the canvas static server constructs MIME types)The fix is to check file extension before falling back to content-based detection:
Steps to Reproduce
canvasHost.enabled: trueopenclaw nodes canvas a2ui push --text "Hello"(or any A2UI JSONL)Expected Behavior
A2UI content should render and persist on the canvas until explicitly replaced.
Environment
Workaround
Bug 2 (MIME type) can be patched in the compiled gateway dist file by adding extension checks before
detectMime(). Bug 1 (auto-navigation) requires rebuilding the macOS app from source — no runtime workaround found.