[Early POC] Add a third-party Canvas MVP for Copilot agent sessions - #335640
Draft
Joaquín Ruales (jruales) wants to merge 1 commit into
Draft
[Early POC] Add a third-party Canvas MVP for Copilot agent sessions#335640Joaquín Ruales (jruales) wants to merge 1 commit into
Joaquín Ruales (jruales) wants to merge 1 commit into
Conversation
Reuse the Copilot runtime Canvas lifecycle and expose local desktop Canvas opening, reopening, and closing through the Integrated Browser. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
Joaquín Ruales (jruales)
September 11, 2026 07:43
View session
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Transient URLs can become persistent when copied, and connection replacement races can target the wrong host.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review tier: Balanced
Findings: 2
New issues introduced by this change (4)
| Severity | Finding |
|---|---|
src/vs/workbench/contrib/browserView/common/browserEditorInput.ts — Copying bypasses transient URL protection |
|
src/vs/workbench/contrib/chat/electron-browser/agentHostCanvas.contribution.ts — Revalidate the connection after the open request |
|
src/vs/workbench/contrib/chat/electron-browser/agentHostCanvas.contribution.ts — Do not route a stale close selection to a new host |
|
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCanvasPicker.ts — Distinguish invalid values from invalid JSON syntax |
What changed in this PR
Adds a desktop proof of concept for third-party Copilot Canvases, integrating runtime-managed Canvas instances with Agent Host sessions and Integrated Browser tabs.
Changes:
- Adds Canvas discovery, lifecycle metadata, launch plumbing, and local/remote management APIs.
- Adds transient Integrated Browser presentation plus open, reopen, and close commands.
- Adds focused backend, UI, accessibility, protocol, and persistence tests.
| File | Description |
|---|---|
src/vs/workbench/workbench.desktop.main.ts |
Loads the Canvas contribution. |
src/vs/workbench/services/agentHost/browser/editorRemoteAgentHostServiceClient.ts |
Forwards remote Canvas operations. |
src/vs/workbench/contrib/terminal/test/browser/agentHostPty.test.ts |
Updates the Agent connection mock. |
src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostCanvasPicker.test.ts |
Tests Canvas selection and JSON input. |
src/vs/workbench/contrib/chat/test/browser/agentSessions/agentHostCanvas.test.ts |
Tests browser presentation lifecycle. |
src/vs/workbench/contrib/chat/test/browser/accessibility/chatAccessibilityHelp.test.ts |
Tests Canvas accessibility guidance. |
src/vs/workbench/contrib/chat/electron-browser/agentHostCanvas.contribution.ts |
Registers commands and session tracking. |
src/vs/workbench/contrib/chat/common/actions/chatActions.ts |
Defines Canvas command identifiers. |
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCanvasPicker.ts |
Implements the catalog and input picker. |
src/vs/workbench/contrib/chat/browser/agentSessions/agentHost/agentHostCanvas.ts |
Presents Canvases in browser editors. |
src/vs/workbench/contrib/chat/browser/actions/chatAccessibilityHelp.ts |
Documents Canvas keyboard workflows. |
src/vs/workbench/contrib/browserView/test/electron-browser/browserEditorInput.test.ts |
Tests transient editor serialization. |
src/vs/workbench/contrib/browserView/electron-browser/browserViewWorkbenchService.ts |
Supports caller IDs and transient views. |
src/vs/workbench/contrib/browserView/common/browserView.ts |
Extends browser creation options. |
src/vs/workbench/contrib/browserView/common/browserEditorInput.ts |
Adds non-persistent browser inputs. |
src/vs/sessions/sessions.desktop.main.ts |
Loads Canvas support in Agents Window. |
src/vs/sessions/contrib/editor/test/browser/editor.contribution.test.ts |
Tests Canvas action targeting and gating. |
src/vs/sessions/contrib/editor/browser/editor.contribution.ts |
Registers the Canvas submenu. |
src/vs/sessions/contrib/editor/browser/addTabActions.ts |
Adds Canvas tab actions. |
src/vs/sessions/browser/menus.ts |
Defines the Canvas submenu. |
src/vs/platform/agentHost/test/node/protocolServerHandler.test.ts |
Tests remote Canvas RPC routing. |
src/vs/platform/agentHost/test/node/copilotSessionLauncher.test.ts |
Tests Canvas launch configuration. |
src/vs/platform/agentHost/test/node/copilotExtensionLaunch.test.ts |
Tests extension launch adaptation. |
src/vs/platform/agentHost/test/node/copilotAgentSession.test.ts |
Registers Canvas services in tests. |
src/vs/platform/agentHost/test/node/copilotAgent.test.ts |
Tests chat materialization without turns. |
src/vs/platform/agentHost/test/node/agentService.test.ts |
Tests Canvas ownership and routing. |
src/vs/platform/agentHost/test/node/agentHostManagementService.test.ts |
Tests local management IPC. |
src/vs/platform/agentHost/test/node/agentHostCanvasController.test.ts |
Tests Canvas state reconciliation. |
src/vs/platform/agentHost/test/electron-browser/localAgentHostService.test.ts |
Tests local management-channel routing. |
src/vs/platform/agentHost/test/electron-browser/agentHostProtocolClient.test.ts |
Tests capability-gated Canvas RPCs. |
src/vs/platform/agentHost/test/common/agentCanvasMeta.test.ts |
Tests metadata and input validation. |
src/vs/platform/agentHost/node/protocolServerHandler.ts |
Handles Canvas extension RPCs. |
src/vs/platform/agentHost/node/copilot/copilotSessionLauncher.ts |
Configures runtime Canvas support. |
src/vs/platform/agentHost/node/copilot/copilotExtensionLaunch.ts |
Builds extension launch specifications. |
src/vs/platform/agentHost/node/copilot/copilotAgentSession.ts |
Registers live SDK Canvas sessions. |
src/vs/platform/agentHost/node/copilot/copilotAgent.ts |
Enables extensions and prepares chats. |
src/vs/platform/agentHost/node/agentService.ts |
Routes direct Canvas operations. |
src/vs/platform/agentHost/node/agentHostServices.ts |
Registers the Canvas controller service. |
src/vs/platform/agentHost/node/agentHostManagementService.ts |
Exposes local Canvas management. |
src/vs/platform/agentHost/node/agentHostCanvasController.ts |
Reconciles runtime Canvas state. |
src/vs/platform/agentHost/electron-browser/localAgentHostService.ts |
Advertises and routes local capabilities. |
src/vs/platform/agentHost/common/meta/agentCanvasMeta.ts |
Defines Canvas metadata contracts. |
src/vs/platform/agentHost/common/agentService.ts |
Extends Agent Host service interfaces. |
src/vs/platform/agentHost/common/agentHostExtensionProtocol.ts |
Defines Canvas extension methods. |
src/vs/platform/agentHost/common/agent.ts |
Adds the Canvas preparation seam. |
src/vs/platform/agentHost/browser/nullAgentHostService.ts |
Implements unsupported Canvas stubs. |
src/vs/platform/agentHost/browser/agentHostProtocolClient.ts |
Sends Canvas extension requests. |
src/vs/platform/agentHost/AGENTS.md |
Documents Canvas architecture and constraints. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| export class BrowserEditorSerializer implements IEditorSerializer { | ||
| canSerialize(editorInput: EditorInput): editorInput is BrowserEditorInput { | ||
| return editorInput instanceof BrowserEditorInput; | ||
| return editorInput instanceof BrowserEditorInput && !editorInput.transient; |
Comment on lines
+208
to
+212
| const opened = await resolution.connection.openCanvas(resolution.backendSession, chat, selection.canvas.extensionId, selection.canvas.canvasTypeId, selection.input); | ||
| const controller = this._sessions.get(resource)?.canvas; | ||
| if (controller) { | ||
| await controller.update([...controller.canvases.filter(canvas => canvas.instanceId !== opened.instanceId), opened]); | ||
| await controller.open(opened.instanceId); |
Comment on lines
+237
to
+242
| const resolution = this._connections.resolveSessionResource(resource); | ||
| if (!resolution) { | ||
| this._notificationService.error(localize('canvas.disconnected', "The agent host is disconnected. Reconnect before closing the canvas.")); | ||
| return; | ||
| } | ||
| await resolution.connection.closeCanvas(resolution.backendSession, URI.parse(selection.chat), selection.instanceId); |
Comment on lines
+65
to
+69
| } catch (error) { | ||
| if (!(error instanceof SyntaxError) && !(error instanceof TypeError)) { | ||
| throw error; | ||
| } | ||
| return localize('canvas.invalidInput', "Enter valid JSON."); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Add a desktop MVP for third-party Copilot Canvases using the existing Copilot runtime extension format and VS Code's Integrated Browser, with the normal browser navigation bar left visible.
Architecture
The Node SDK runs in Agent Host and talks to the Copilot runtime. The runtime discovers compatible extensions, launches their backend processes, and owns their Canvas tools and lifecycle. An extension supplies an HTTP(S) URL, which VS Code renders in the Integrated Browser. This change adds the host/client plumbing and UI; it does not reimplement Canvas execution or modify the runtime.
SDK prerequisite
Companion SDK change: github/copilot-sdk#2618.
The current installed Node SDK (1.0.13) does not expose a usable extension-launch callback. The companion SDK draft adds
onExtensionLaunchand startup registration of the existing runtime launch-provider protocol.VS Code's
copilotExtensionLaunch.tsonly supplies an executable, the runtime's own bundled bootstrap, and the extension entrypoint. Discovery, permission enforcement, spawning, and termination remain runtime-owned.Standalone extension loading is enabled only when the SDK advertises
supportsExtensionLaunchProvider. This draft does not update the package dependency and will not provide standalone Canvas extensions with the stock SDK. It needs the companion SDK built locally for testing, then a dependency update after that change ships.The local demo used
VSCODE_DEV_INJECT_NODE_MODULE_LOOKUP_PATHwith an ignored node-modules overlay pointing@github/copilot-sdkat the built sibling SDK checkout. No machine-specific dependency paths or overlay files are committed. Setup details are documented insrc/vs/platform/agentHost/AGENTS.md.Validation performed during implementation
npm run valid-layers-check, andgit diff --checkpassed.list_canvas_capabilities,open_canvas, and one approvedinvoke_canvas_actionincrement completed; the server and assistant both returned count 1.Known limitations / follow-up
page.reload()was followed by aborted browser-navigation notifications. A full app restart and supported Developer: Reload Window validation did not reproduce those errors; the raw-reload behavior has not been fixed.Kept as a draft to share the architecture and MVP for review before SDK/API stabilization and lifecycle hardening.