Skip to content

[codex] Implement Canvas A2UI visual workspace#78

Merged
Telli merged 2 commits into
mainfrom
codex/canvas-a2ui-visual-workspace
Apr 28, 2026
Merged

[codex] Implement Canvas A2UI visual workspace#78
Telli merged 2 commits into
mainfrom
codex/canvas-a2ui-visual-workspace

Conversation

@Telli
Copy link
Copy Markdown
Contributor

@Telli Telli commented Apr 28, 2026

Summary

Implements Canvas + A2UI v1 as a first-party, session-scoped visual workspace for websocket clients.

Changes

  • Adds Canvas configuration, websocket envelope fields, A2UI v0.8 JSONL validation, and structured A2UI event message fields.
  • Adds a gateway Canvas command broker and native tools for present, hide, navigate, snapshot, A2UI push/reset, and local A2UI eval.
  • Implements public-bind hardening so Canvas forwarding is disabled/refused unless explicitly allowed on public binds.
  • Adds webchat Canvas hosting with A2UI rendering, sandboxed local HTML, eval results, snapshots, and interaction events.
  • Adds a Companion Canvas tab with native Avalonia A2UI renderers, events, snapshots, and unsupported diagnostics for local HTML/eval.
  • Updates docs and compatibility guidance from proposal to supported v1 behavior.

Validation

  • dotnet test src/OpenClaw.Tests/OpenClaw.Tests.csproj --no-restore --filter "FullyQualifiedName~A2UiFrameValidatorTests|FullyQualifiedName~CanvasCommandBrokerTests|FullyQualifiedName~CanvasToolTests|FullyQualifiedName~CompanionCanvasTests|FullyQualifiedName~WebSocketChannelTests|FullyQualifiedName~GatewaySecurityHardeningTests|FullyQualifiedName~GatewayBootstrapExtensionsTests|FullyQualifiedName~DocsConsistencyTests" passed: 54/54.
  • Webchat script syntax check with Node passed.
  • Full dotnet test src/OpenClaw.Tests/OpenClaw.Tests.csproj --no-restore currently has one unrelated local environment failure: missing Playwright Chromium executable for BrowserToolTests.BrowserTool_CanNavigateAndGetText; the remaining 995 tests pass.

Comment thread src/OpenClaw.Gateway/wwwroot/webchat.html Fixed
Comment thread src/OpenClaw.Gateway/wwwroot/webchat.html Fixed
Comment thread src/OpenClaw.Gateway/wwwroot/webchat.html Fixed
@Telli Telli marked this pull request as ready for review April 28, 2026 01:05
Copilot AI review requested due to automatic review settings April 28, 2026 01:05
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 28, 2026

🤖 Augment PR Summary

Summary: Adds a first-party, session-scoped Canvas + A2UI visual workspace for websocket clients.

Changes:

  • Introduces Canvas configuration (OpenClaw:Canvas) and extends websocket envelopes to carry Canvas/A2UI command, result, and event fields.
  • Adds A2UiFrameValidator for A2UI v0.8 JSONL validation and rejects unsupported v0.9 createSurface frames.
  • Implements a gateway CanvasCommandBroker to forward commands to the active websocket session, track pending acks/results, log runtime events, and enforce timeouts/size limits.
  • Adds native tools (canvas_present, canvas_hide, canvas_navigate, canvas_snapshot, a2ui_push, a2ui_reset, a2ui_eval) for controlling the workspace.
  • Hardens public-bind behavior by refusing/auto-disabling Canvas forwarding unless explicitly opted in.
  • Extends webchat to host a Canvas side panel with A2UI rendering, sandboxed local HTML, snapshots, and interaction event reporting.
  • Adds a Companion “Canvas” tab with native Avalonia renderers, snapshot/event plumbing, and explicit unsupported diagnostics for local HTML/eval.
  • Adds targeted unit tests covering validation, broker behavior, tools, websocket routing, and security hardening.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review completed. 4 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

<TextBlock Text="{Binding CanvasStatus}" TextWrapping="Wrap" />
<TextBlock Text="{Binding CanvasHtmlStatus}" FontSize="11" Opacity="0.65"
TextWrapping="Wrap"
IsVisible="{Binding CanvasHtmlStatus, Converter={x:Static ObjectConverters.IsNotNull}}" />
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/OpenClaw.Companion/Views/MainWindow.axaml:88CanvasHtmlStatus is initialized to "" (not null), so ObjectConverters.IsNotNull will keep this TextBlock visible even when there’s no status text, likely leaving an empty line in the Canvas header area.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

if (!root.TryGetProperty("value", out var value) || value.ValueKind != JsonValueKind.Number)
return 0;
var number = value.GetDouble();
return number <= 1 ? number * 100 : Math.Clamp(number, 0, 100);
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/OpenClaw.Companion/ViewModels/A2UiFrameItem.cs:126BuildProgressValue() will return negative percentages if the incoming numeric value is negative (because the number <= 1 branch multiplies by 100 without clamping), which can drive the UI progress bar below its expected range.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

if (!TryGetRequiredString(args.RootElement, "frames", out var frames, out var error))
return error;

var validation = A2UiFrameValidator.ValidateJsonl(frames, Config.Canvas.MaxFramesPerPush, Config.Canvas.MaxCommandBytes);
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/OpenClaw.Gateway/Tools/CanvasTools.cs:188ValidateJsonl(..., maxBytes: Config.Canvas.MaxCommandBytes) only bounds the raw frames payload, but the broker enforces MaxCommandBytes on the full serialized envelope; payloads near the limit can validate here and still fail later with “Canvas command exceeds … bytes.”

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.


private async Task SendCanvasSnapshotResultAsync(WsServerEnvelope envelope)
{
var snapshot = BuildCanvasSnapshotJson(envelope.SurfaceId);
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/OpenClaw.Companion/ViewModels/MainWindowViewModel.Canvas.cs:179BuildCanvasSnapshotJson() serializes all accumulated frames/values without any explicit bounding, so after many pushes the snapshot can exceed the gateway’s MaxSnapshotBytes and cause canvas_snapshot to fail even though the client returns success: true.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@Telli Telli merged commit a61b589 into main Apr 28, 2026
15 of 16 checks passed
@Telli Telli deleted the codex/canvas-a2ui-visual-workspace branch April 28, 2026 01:41
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.

2 participants