Skip to content

feat: wire WebView2 native↔SPA bridge in CanvasWindow#259

Open
AlexAlves87 wants to merge 1 commit intoopenclaw:masterfrom
AlexAlves87:feat/canvas-bridge-parity
Open

feat: wire WebView2 native↔SPA bridge in CanvasWindow#259
AlexAlves87 wants to merge 1 commit intoopenclaw:masterfrom
AlexAlves87:feat/canvas-bridge-parity

Conversation

@AlexAlves87
Copy link
Copy Markdown
Contributor

@AlexAlves87 AlexAlves87 commented May 1, 2026

Summary

Adds the bidirectional WebView2 bridge to CanvasWindow and removes the fragile ExecuteScriptAsync heuristic paths, closing the remaining item on the #191 checklist after #192 landed the WebChatWindow half.

Native → SPA

canvasWindow.PostBridgeMessage(WebBridgeMessage.TypeRecordingStart);

SPA → native

canvasWindow.BridgeMessageReceived += (_, msg) => { /* msg.Type, msg.PayloadJson */ };

Why

The #191 checklist had one item outstanding after #192:

[ ] Add equivalent bridge surface to CanvasWindow, replacing fragile ExecuteScriptAsync message paths where appropriate

SendA2UIMessageAsync and ResetA2UIAsync used 11 and 6 heuristic fallbacks respectively (window.__a2ui, window.a2ui, window.A2UI, dispatchEvent, postMessage…) to push messages into the SPA — the exact fragile pattern the issue calls out. Both methods had no active callers; the A2UI path is now served by the native A2UICanvasWindow renderer. They are removed and the bridge is the replacement.

Trust boundary

IsTrustedBridgeSource accepts messages from exactly two origins:

  • _trustedGatewayOrigin — the gateway configured via SetTrustedGatewayOrigin
  • https://openclaw-canvas.local — the local virtual host for canvas files

Everything else is rejected with a warning log entry.

What is not changed

  • EvalAsync — untouched; it is the canvas.eval agent API, not a messaging path
  • EnsureA2UIHostAsync — untouched; uses Navigate, not the heuristic pattern
  • NodeService — no changes
  • A2UICanvasWindow — not touched

Tests

Source-scan added in TrayMenuWindowMarkupTests asserting presence of BridgeMessageReceived, IsTrustedBridgeSource, openclaw-canvas.local, dispatcher marshaling, PostWebMessageAsJson, SanitizeBridgeLogValue, and WebMessageReceived cleanup in OnWindowClosed.

Validation

build.ps1 ✅ — OpenClaw.Shared.Tests 1100/1100 ✅ — OpenClaw.Tray.Tests 407/407 ✅

Adds BridgeMessageReceived + PostBridgeMessage to CanvasWindow following
the same pattern as WebChatWindow (c7630fa), closing the CanvasWindow
item on the openclaw#191 checklist. Removes SendA2UIMessageAsync, ResetA2UIAsync,
and their heuristic ExecuteScriptAsync helpers; both had no active callers
and are replaced by the bridge. IsTrustedBridgeSource accepts only
_trustedGatewayOrigin and openclaw-canvas.local. Source-scan test added
in TrayMenuWindowMarkupTests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@AlexAlves87 AlexAlves87 force-pushed the feat/canvas-bridge-parity branch from 85c44b9 to aa449d2 Compare May 2, 2026 01:46
@AlexAlves87
Copy link
Copy Markdown
Contributor Author

The failing test (LocalCommandRunnerIntegrationTests.Run_WithEnvVars) doesn't seem to be exercised by this PR, as no changes touch LocalCommandRunner or env var handling.

I noticed a recent run on 0f54bc1 showing a different integration test failing in the same pattern, which suggests this might be intermittent CI flakiness rather than a regression.

Happy to trigger a re-run if that would help move this forward!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant