Add host-side canvas declaration API and canvasProvider to Java SDK#1848
Add host-side canvas declaration API and canvasProvider to Java SDK#1848jmoseley wants to merge 2 commits into
Conversation
Brings the Java SDK to parity with Rust/Node/.NET for the host-facing canvas API. Previously Java only had the read-side open-canvases snapshot and could not declare canvases, register a provider handler, or supply provider identity. Adds five public types in com.github.copilot.rpc (all @CopilotExperimental): CanvasDeclaration, ExtensionInfo, CanvasProviderIdentity, CanvasHandler, and CanvasException. Wires canvas declaration fields (canvases, requestCanvasRenderer, requestExtensions, extensionSdkPath, extensionInfo, canvasProvider) through SessionConfig/ResumeSessionConfig and the Jackson wire DTOs, mapped by SessionRequestBuilder. Routes inbound canvas.open / canvas.close / canvas.action.invoke provider callbacks in RpcHandlerDispatcher to the registered CanvasHandler on CopilotSession. Also adds the canvasProvider (CanvasProviderIdentity with required id and optional name) field on session.create and session.resume, matching runtime PR #10519 and the sibling Rust/Node/.NET work. It is a hand-registered JSON-RPC field serialized as canvasProvider with nested id/name; name is omitted from the wire when null. Fully optional and back-compatible. Tests: CanvasHostApiTest asserts the create/resume wire JSON (extensionInfo, canvasProvider id/name, name-omitted, fields-omitted-when-unset, canvasHandler never serialized) mirroring the Rust session tests. CanvasIT adds three E2E tests (list, open, invoke action) driving the full canvas round-trip against the live CLI via the replay proxy, with two new handcrafted snapshots. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This pull request brings the Java SDK up to parity with other Copilot SDKs by adding host-side canvas declaration support (create/resume wire fields + handler callbacks), plus the new session-level canvasProvider identity.
Changes:
- Adds new experimental public canvas-related RPC types (
CanvasDeclaration,ExtensionInfo,CanvasProviderIdentity,CanvasHandler,CanvasException) and threads them throughSessionConfig/ResumeSessionConfig. - Extends
session.create/session.resumerequest DTOs andSessionRequestBuildermapping to include canvas declaration + identity fields. - Registers and routes inbound
canvas.open/canvas.close/canvas.action.invokerequests to a session-registeredCanvasHandler, including structured error responses; adds unit + E2E coverage and snapshots.
Show a summary per file
| File | Description |
|---|---|
| test/snapshots/canvas/canvas_open_round_trip.yaml | Adds replay-proxy fixture for canvas open round-trip E2E scenario (no CAPI calls). |
| test/snapshots/canvas/canvas_invoke_action_round_trip.yaml | Adds replay-proxy fixture for canvas action invocation E2E scenario (no CAPI calls). |
| java/src/test/java/com/github/copilot/CanvasIT.java | New Java failsafe IT covering list/open/action canvas round-trips via replay proxy. |
| java/src/test/java/com/github/copilot/CanvasHostApiTest.java | New unit tests asserting create/resume wire JSON mapping and handler/exception defaults. |
| java/src/main/java/com/github/copilot/SessionRequestBuilder.java | Wires new canvas/extension/provider config fields into create/resume requests and registers handler on session. |
| java/src/main/java/com/github/copilot/RpcHandlerDispatcher.java | Adds JSON-RPC handlers for canvas.open, canvas.close, canvas.action.invoke and structured error responses. |
| java/src/main/java/com/github/copilot/rpc/SessionConfig.java | Adds canvas declarations, extension identity, provider identity, and non-serialized CanvasHandler. |
| java/src/main/java/com/github/copilot/rpc/ResumeSessionConfig.java | Adds resume-time canvas declarations, open-canvas snapshot, and non-serialized CanvasHandler. |
| java/src/main/java/com/github/copilot/rpc/CreateSessionRequest.java | Adds new wire fields for canvas declarations/identities on session.create. |
| java/src/main/java/com/github/copilot/rpc/ResumeSessionRequest.java | Adds new wire fields for canvas declarations/identities on session.resume. |
| java/src/main/java/com/github/copilot/rpc/ExtensionInfo.java | New public experimental type for stable extension/provider identity on the wire. |
| java/src/main/java/com/github/copilot/rpc/CanvasProviderIdentity.java | New public experimental type for session-level canvas provider identity. |
| java/src/main/java/com/github/copilot/rpc/CanvasHandler.java | New public experimental callback interface for inbound canvas lifecycle/action requests. |
| java/src/main/java/com/github/copilot/rpc/CanvasException.java | New public experimental exception type carrying machine-readable error codes. |
| java/src/main/java/com/github/copilot/rpc/CanvasDeclaration.java | New public experimental type describing declared canvases sent on create/resume. |
| java/src/main/java/com/github/copilot/JsonRpcClient.java | Extends error response sending to optionally include structured data. |
| java/src/main/java/com/github/copilot/CopilotSession.java | Stores/registers CanvasHandler and exposes internal routing helpers for canvas callbacks. |
Review details
- Files reviewed: 17/17 changed files
- Comments generated: 3
- Review effort level: Low
This comment has been minimized.
This comment has been minimized.
Address Cloud Code Review feedback: the canvas.open / canvas.close / canvas.action.invoke handlers caught synchronous failures (e.g. malformed params from treeToValue, or any logic before the CompletableFuture chain is attached) but only logged them, leaving the caller without a response. Send a structured canvas error reply in the catch block so the provider callback always completes instead of hanging. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Cross-SDK Consistency Review ✅Summary: This PR maintains excellent cross-SDK consistency and is part of a well-coordinated companion PR pair. Companion PR relationshipThis PR (#1848) and #1847 are designed to be merged together:
Together they bring all six SDKs to full parity on the canvas host-side declaration API. Canvas host-side API parity check
API naming consistencyJava's naming follows language conventions while remaining semantically parallel:
No outstanding consistency gapsOnce both #1847 and #1848 are merged, all six SDKs will be fully consistent on the canvas host-side declaration API surface. There are no unaddressed inconsistencies in this PR.
|
Why
The Java SDK was the only SDK without host-side canvas declaration support. Unlike Rust/Node/.NET, Java's
SessionConfig/ResumeSessionConfighad nocanvasesdeclaration field and noextensionInfoidentity, so a host could not declare canvases on session create/resume, register a canvas handler, or supply provider identity. Java only had the read-side open-canvases snapshot. This brings Java to full parity and adds the new session-levelcanvasProvideridentity from runtime PR #10519.What
Five new public types in
com.github.copilot.rpc(all@CopilotExperimental, Jackson-annotated, fluent setters + getters, Javadoc):CanvasDeclaration—{id, displayName, description, inputSchema?, actions?}ExtensionInfo—{source, name}provider identityCanvasProviderIdentity—{id, name?}(the new field)CanvasHandler— interface withonOpen+ defaultonClose/onActionCanvasException— carries acode;noHandler()->canvas_action_no_handlerWiring:
canvases,requestCanvasRenderer,requestExtensions,extensionSdkPath,extensionInfo,canvasProvider) added toSessionConfig/ResumeSessionConfigand the Jackson wire DTOs (CreateSessionRequest/ResumeSessionRequest), mapped bySessionRequestBuilder.canvas.open/canvas.close/canvas.action.invokeprovider callbacks routed inRpcHandlerDispatcherto the registeredCanvasHandleronCopilotSession(withCompletableFutureresults and a structured error envelope).session.getRpc().canvasAPI; no new accessor needed.canvasProvideris added on bothsession.createandsession.resume, serialized ascanvasProviderwith nestedid/name(name omitted from the wire when null). It is a hand-registered JSON-RPC field (not inapi.schema.json), matching the sibling Rust/Node/.NET work exactly. Fully optional and back-compatible.Notes for reviewers
canvasHandlerlives only on the config object and is never serialized (test-asserted).java/src/generated/; tests use public APIs only.session.canvas.*stream events were already generated and surfaced through the typed event stream, so this PR only fills the host-side declaration gap.mvn spotless:apply && mvn verifypasses (checkstyle 0 violations, all unit tests + 16 IT including 3 newCanvasIT, multi-release JAR built). The full build requires JDK 25+.Tests
CanvasHostApiTest(8 unit tests) asserts the create/resume wire JSON:extensionInfo,canvasProviderid/name, name-omitted-when-null, fields-omitted-when-unset, and thatcanvasHandleris never serialized; mirrors the Rust session tests.CanvasIT(3 E2E tests) drives the full canvas round-trip (list, open, invoke action) against the live CLI via the replay proxy, with two new handcrafted snapshots.