diff --git a/dotnet/src/Canvas.cs b/dotnet/src/Canvas.cs index 6a6134e18..e81246948 100644 --- a/dotnet/src/Canvas.cs +++ b/dotnet/src/Canvas.cs @@ -2,9 +2,11 @@ * Copyright (c) Microsoft Corporation. All rights reserved. *--------------------------------------------------------------------------------------------*/ +using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; @@ -95,22 +97,22 @@ public sealed class CanvasHostCapabilities public sealed class CanvasOpenContext { /// Session that requested the canvas. - public string SessionId { get; init; } = string.Empty; + public string SessionId { get; set; } = string.Empty; /// Owning provider identifier. - public string ExtensionId { get; init; } = string.Empty; + public string ExtensionId { get; set; } = string.Empty; /// Canvas id from the declaring . - public string CanvasId { get; init; } = string.Empty; + public string CanvasId { get; set; } = string.Empty; /// Stable instance id supplied by the runtime. - public string InstanceId { get; init; } = string.Empty; + public string InstanceId { get; set; } = string.Empty; /// Validated input payload. - public JsonElement Input { get; init; } + public JsonElement Input { get; set; } /// Host capabilities supplied by the runtime. - public CanvasHostContext? Host { get; init; } + public CanvasHostContext? Host { get; set; } } /// Context handed to . @@ -118,25 +120,25 @@ public sealed class CanvasOpenContext public sealed class CanvasActionContext { /// Session that invoked the action. - public string SessionId { get; init; } = string.Empty; + public string SessionId { get; set; } = string.Empty; /// Owning provider identifier. - public string ExtensionId { get; init; } = string.Empty; + public string ExtensionId { get; set; } = string.Empty; /// Canvas id targeted by the action. - public string CanvasId { get; init; } = string.Empty; + public string CanvasId { get; set; } = string.Empty; /// Instance id targeted by the action. - public string InstanceId { get; init; } = string.Empty; + public string InstanceId { get; set; } = string.Empty; /// Action name from . - public string ActionName { get; init; } = string.Empty; + public string ActionName { get; set; } = string.Empty; /// Validated input payload. - public JsonElement Input { get; init; } + public JsonElement Input { get; set; } /// Host capabilities supplied by the runtime. - public CanvasHostContext? Host { get; init; } + public CanvasHostContext? Host { get; set; } } /// Context handed to a canvas's close lifecycle hook. @@ -144,19 +146,19 @@ public sealed class CanvasActionContext public sealed class CanvasLifecycleContext { /// Session owning the canvas instance. - public string SessionId { get; init; } = string.Empty; + public string SessionId { get; set; } = string.Empty; /// Owning provider identifier. - public string ExtensionId { get; init; } = string.Empty; + public string ExtensionId { get; set; } = string.Empty; /// Canvas id from the declaring . - public string CanvasId { get; init; } = string.Empty; + public string CanvasId { get; set; } = string.Empty; /// Instance id this lifecycle event applies to. - public string InstanceId { get; init; } = string.Empty; + public string InstanceId { get; set; } = string.Empty; /// Host capabilities supplied by the runtime. - public CanvasHostContext? Host { get; init; } + public CanvasHostContext? Host { get; set; } } /// Structured error returned from canvas handlers. @@ -166,12 +168,12 @@ public sealed class CanvasLifecycleContext /// in a generic canvas_handler_error envelope. /// [Experimental(Diagnostics.Experimental)] -public sealed class CanvasError : Exception +public sealed class CanvasException : Exception { - /// Initializes a new . + /// Initializes a new . /// Machine-readable error code. /// Human-readable message. - public CanvasError(string code, string message) : base(message) + public CanvasException(string code, string message) : base(message) { Code = code; } @@ -182,13 +184,13 @@ public CanvasError(string code, string message) : base(message) /// /// Default error returned when a custom action has no handler. /// - public static CanvasError NoHandler() => new( + public static CanvasException NoHandler() => new( "canvas_action_no_handler", "No handler implemented for this canvas action"); } /// -/// Internal helpers used by the session runtime to translate +/// Internal helpers used by the session runtime to translate /// (and other handler-thrown exceptions) into structured JSON-RPC error responses. /// internal static class CanvasErrorHelpers @@ -203,31 +205,17 @@ public static LocalRpcInvocationException HandlerError(string message) => Build( "canvas_handler_error", message); - public static LocalRpcInvocationException ToRpcException(CanvasError error) => Build(error.Code, error.Message); + public static LocalRpcInvocationException ToRpcException(CanvasException error) => Build(error.Code, error.Message); private static LocalRpcInvocationException Build(string code, string message) { - var json = JsonSerializer.Serialize( - new CanvasErrorPayload { Code = code, Message = message }, - CanvasJsonContext.Default.CanvasErrorPayload); - using var doc = JsonDocument.Parse(json); - return new LocalRpcInvocationException(InternalError, message, doc.RootElement.Clone()); - } - - internal sealed class CanvasErrorPayload - { - [JsonPropertyName("code")] - public string Code { get; set; } = string.Empty; - - [JsonPropertyName("message")] - public string Message { get; set; } = string.Empty; + JsonElement payload = JsonSerializer.SerializeToElement( + new JsonObject { ["code"] = code, ["message"] = message }, + TypesJsonContext.Default.JsonObject); + return new LocalRpcInvocationException(InternalError, message, payload); } } -[JsonSourceGenerationOptions(PropertyNamingPolicy = JsonKnownNamingPolicy.CamelCase)] -[JsonSerializable(typeof(CanvasErrorHelpers.CanvasErrorPayload))] -internal partial class CanvasJsonContext : JsonSerializerContext; - /// /// Provider-side canvas lifecycle handler. /// @@ -259,7 +247,7 @@ public interface ICanvasHandler /// /// Handle a non-lifecycle action declared by the canvas. - /// Default: throws . + /// Default: throws . /// Task OnActionAsync(CanvasActionContext context, CancellationToken cancellationToken); } @@ -284,5 +272,5 @@ public virtual Task OnCloseAsync(CanvasLifecycleContext context, CancellationTok /// public virtual Task OnActionAsync(CanvasActionContext context, CancellationToken cancellationToken) - => Task.FromException(CanvasError.NoHandler()); + => Task.FromException(CanvasException.NoHandler()); } diff --git a/dotnet/src/JsonRpc.cs b/dotnet/src/JsonRpc.cs index df7170373..1346519ea 100644 --- a/dotnet/src/JsonRpc.cs +++ b/dotnet/src/JsonRpc.cs @@ -486,6 +486,13 @@ private async Task HandleIncomingMethodAsync(string methodName, JsonElement mess } catch (Exception ex) when (ex is not OperationCanceledException) { + // `InvokeHandlerAsync` dispatches handlers via reflection + // (`Delegate.DynamicInvoke` / `MethodInfo.Invoke`), which wraps + // any exception thrown inside the user-supplied handler in a + // `TargetInvocationException`. Unwrap so we surface the original + // failure (e.g. `LocalRpcInvocationException`, `CanvasException`) + // to the JSON-RPC error response instead of the reflection + // wrapper. var actual = ex is TargetInvocationException tie && tie.InnerException != null ? tie.InnerException : ex; if (_logger.IsEnabled(LogLevel.Debug)) { diff --git a/dotnet/src/Session.cs b/dotnet/src/Session.cs index bd2309187..fadee7fe2 100644 --- a/dotnet/src/Session.cs +++ b/dotnet/src/Session.cs @@ -914,7 +914,7 @@ internal async ValueTask HandleCanvasOpenAsync( { return await handler.OnOpenAsync(ctx, CancellationToken.None).ConfigureAwait(false); } - catch (CanvasError ce) + catch (CanvasException ce) { throw CanvasErrorHelpers.ToRpcException(ce); } @@ -943,7 +943,7 @@ internal async ValueTask HandleCanvasCloseAsync( { await handler.OnCloseAsync(ctx, CancellationToken.None).ConfigureAwait(false); } - catch (CanvasError ce) + catch (CanvasException ce) { throw CanvasErrorHelpers.ToRpcException(ce); } @@ -977,7 +977,7 @@ internal async ValueTask HandleCanvasActionAsync( var result = await handler.OnActionAsync(ctx, CancellationToken.None).ConfigureAwait(false); return SerializeActionResult(result); } - catch (CanvasError ce) + catch (CanvasException ce) { throw CanvasErrorHelpers.ToRpcException(ce); } @@ -987,15 +987,15 @@ internal async ValueTask HandleCanvasActionAsync( } } + // Cached JsonElement representing the JSON literal `null`. Hoisted because + // canvas action handlers frequently return null/void, and parsing "null" + // on every call would allocate a fresh JsonDocument. + private static readonly JsonElement NullJsonElement = JsonSerializer.SerializeToElement(null, TypesJsonContext.Default.Object); + private static JsonElement SerializeActionResult(object? value) { var element = CopilotClient.ToJsonElementForWire(value); - if (element.HasValue) - { - return element.Value; - } - using var doc = JsonDocument.Parse("null"); - return doc.RootElement.Clone(); + return element ?? NullJsonElement; } #pragma warning restore GHCP001 diff --git a/dotnet/src/Types.cs b/dotnet/src/Types.cs index a02a5db3a..65e07385e 100644 --- a/dotnet/src/Types.cs +++ b/dotnet/src/Types.cs @@ -9,6 +9,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.Json.Serialization; namespace GitHub.Copilot; @@ -3085,6 +3086,7 @@ public sealed class SystemMessageTransformRpcResponse [JsonSerializable(typeof(ToolResultObject))] [JsonSerializable(typeof(JsonElement))] [JsonSerializable(typeof(JsonElement?))] +[JsonSerializable(typeof(JsonObject))] [JsonSerializable(typeof(object))] [JsonSerializable(typeof(Dictionary))] [JsonSerializable(typeof(string[]))] diff --git a/dotnet/test/Unit/CanvasTests.cs b/dotnet/test/Unit/CanvasTests.cs index fc5db84aa..80a18a5e4 100644 --- a/dotnet/test/Unit/CanvasTests.cs +++ b/dotnet/test/Unit/CanvasTests.cs @@ -85,18 +85,18 @@ public async Task CanvasHandlerBase_DefaultOnClose_Completes() } [Fact] - public async Task CanvasHandlerBase_DefaultOnAction_ThrowsNoHandlerCanvasError() + public async Task CanvasHandlerBase_DefaultOnAction_ThrowsNoHandlerCanvasException() { var handler = new TestHandler(); - var ex = await Assert.ThrowsAsync( + var ex = await Assert.ThrowsAsync( () => handler.OnActionAsync(new CanvasActionContext(), CancellationToken.None)); Assert.Equal("canvas_action_no_handler", ex.Code); } [Fact] - public void CanvasError_NoHandler_HasExpectedCode() + public void CanvasException_NoHandler_HasExpectedCode() { - var err = CanvasError.NoHandler(); + var err = CanvasException.NoHandler(); Assert.Equal("canvas_action_no_handler", err.Code); Assert.False(string.IsNullOrEmpty(err.Message)); } diff --git a/go/canvas.go b/go/canvas.go index 2d122db29..f294a880b 100644 --- a/go/canvas.go +++ b/go/canvas.go @@ -14,6 +14,8 @@ import ( // CanvasDeclaration is the declarative metadata for a single canvas, sent over // the wire on `session.create` / `session.resume`. +// +// Experimental: CanvasDeclaration is part of an experimental API and may change or be removed. type CanvasDeclaration struct { // ID is the canvas identifier, unique within the declaring connection. ID string `json:"id"` @@ -28,6 +30,8 @@ type CanvasDeclaration struct { } // CanvasOpenResponse is the response returned from CanvasHandler.OnOpen. +// +// Experimental: CanvasOpenResponse is part of an experimental API and may change or be removed. type CanvasOpenResponse struct { // URL the host should render. Optional for canvases with no visual surface. URL *string `json:"url,omitempty"` @@ -38,18 +42,24 @@ type CanvasOpenResponse struct { } // CanvasHostContext carries host capability hints passed to canvas provider callbacks. +// +// Experimental: CanvasHostContext is part of an experimental API and may change or be removed. type CanvasHostContext struct { // Capabilities describes host feature support relevant to canvases. Capabilities CanvasHostCapabilities `json:"capabilities"` } // CanvasHostCapabilities describes host capability details passed to canvas provider callbacks. +// +// Experimental: CanvasHostCapabilities is part of an experimental API and may change or be removed. type CanvasHostCapabilities struct { // Canvases indicates whether the host supports canvas rendering. Canvases bool `json:"canvases"` } // CanvasOpenContext is the context handed to CanvasHandler.OnOpen. +// +// Experimental: CanvasOpenContext is part of an experimental API and may change or be removed. type CanvasOpenContext struct { // SessionID is the session that requested the canvas. SessionID string @@ -66,6 +76,8 @@ type CanvasOpenContext struct { } // CanvasActionContext is the context handed to CanvasHandler.OnAction. +// +// Experimental: CanvasActionContext is part of an experimental API and may change or be removed. type CanvasActionContext struct { // SessionID is the session that invoked the action. SessionID string @@ -84,6 +96,8 @@ type CanvasActionContext struct { } // CanvasLifecycleContext is the context handed to a canvas's close lifecycle hook. +// +// Experimental: CanvasLifecycleContext is part of an experimental API and may change or be removed. type CanvasLifecycleContext struct { // SessionID is the session owning the canvas instance. SessionID string @@ -102,6 +116,8 @@ type CanvasLifecycleContext struct { // Wire envelope: // // { "code": "", "message": "" } +// +// Experimental: CanvasError is part of an experimental API and may change or be removed. type CanvasError struct { // Code is the machine-readable error code. Code string `json:"code"` @@ -115,11 +131,15 @@ func (e *CanvasError) Error() string { } // NewCanvasError constructs a new error envelope with the given code and message. +// +// Experimental: NewCanvasError is part of an experimental API and may change or be removed. func NewCanvasError(code, message string) *CanvasError { return &CanvasError{Code: code, Message: message} } // CanvasErrorNoHandler is the default error returned when a custom action has no handler. +// +// Experimental: CanvasErrorNoHandler is part of an experimental API and may change or be removed. func CanvasErrorNoHandler() *CanvasError { return NewCanvasError( "canvas_action_no_handler", @@ -140,6 +160,8 @@ func CanvasErrorNoHandler() *CanvasError { // // Embed CanvasHandlerDefaults to inherit no-op defaults for OnClose and a // "no handler" error for OnAction. +// +// Experimental: CanvasHandler is part of an experimental API and may change or be removed. type CanvasHandler interface { OnOpen(ctx context.Context, c CanvasOpenContext) (CanvasOpenResponse, error) OnClose(ctx context.Context, c CanvasLifecycleContext) error @@ -155,6 +177,8 @@ type CanvasHandler interface { // copilot.CanvasHandlerDefaults // } // func (h *myHandler) OnOpen(ctx context.Context, c copilot.CanvasOpenContext) (copilot.CanvasOpenResponse, error) { ... } +// +// Experimental: CanvasHandlerDefaults is part of an experimental API and may change or be removed. type CanvasHandlerDefaults struct{} // OnClose returns nil by default. @@ -224,6 +248,8 @@ func (p *canvasInvokeParams) toActionContext() CanvasActionContext { // ExtensionInfo carries stable extension identity for session participants // that provide canvases. +// +// Experimental: ExtensionInfo is part of an experimental API and may change or be removed. type ExtensionInfo struct { // Source is the extension namespace/source, e.g. "github-app". Source string `json:"source"` diff --git a/nodejs/src/canvas.ts b/nodejs/src/canvas.ts index 738dfc851..321f105c2 100644 --- a/nodejs/src/canvas.ts +++ b/nodejs/src/canvas.ts @@ -11,9 +11,18 @@ * routes those requests by `canvasId` to the in-process handlers bound by * `createCanvas`. Re-opening with an existing `instanceId` is how the host * focuses an existing panel; reload is a renderer-only concern. + * + * **Experimental.** All exports in this module are part of an experimental + * wire-protocol surface and may change or be removed in future SDK or CLI + * releases. */ -/** JSON Schema object used for canvas inputs. */ +/** + * JSON Schema object used for canvas inputs. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export type CanvasJsonSchema = Record; /** @@ -24,6 +33,9 @@ export type CanvasJsonSchema = Record; * * Names MUST NOT start with `canvas.` — that prefix is reserved for * lifecycle verbs. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. */ export interface CanvasAction { /** Action identifier, unique within the canvas. */ @@ -39,6 +51,9 @@ export interface CanvasAction { /** * Declarative metadata for a single canvas, serialized over the wire on * `session.create` / `session.resume`. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. */ export interface CanvasDeclaration { /** Canvas id, unique within the declaring connection. */ @@ -53,7 +68,12 @@ export interface CanvasDeclaration { actions?: Omit[]; } -/** Response returned from `open`. */ +/** + * Response returned from `open`. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export interface CanvasOpenResponse { /** URL the host should render. Optional for native canvases. */ url?: string; @@ -63,14 +83,33 @@ export interface CanvasOpenResponse { status?: string; } -/** Host capabilities passed to canvas callbacks. */ +/** + * Host capability flags carried by {@link CanvasHostContext.capabilities}. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ +export interface CanvasHostCapabilities { + /** Whether the host supports canvas rendering. */ + canvases?: boolean; +} + +/** + * Host capabilities passed to canvas callbacks. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export interface CanvasHostContext { - capabilities?: { - canvases?: boolean; - }; + capabilities?: CanvasHostCapabilities; } -/** Context handed to a canvas's `open` handler. */ +/** + * Context handed to a canvas's `open` handler. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export interface CanvasOpenContext { /** Session that requested the canvas. */ sessionId: string; @@ -86,7 +125,12 @@ export interface CanvasOpenContext { host?: CanvasHostContext; } -/** Context handed to a canvas action handler. */ +/** + * Context handed to a canvas action handler. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export interface CanvasActionContext { /** Session that invoked the action. */ sessionId: string; @@ -104,7 +148,12 @@ export interface CanvasActionContext { host?: CanvasHostContext; } -/** Context handed to a canvas's `onClose` handler. */ +/** + * Context handed to a canvas's `onClose` handler. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export interface CanvasLifecycleContext { /** Session owning the canvas instance. */ sessionId: string; @@ -118,7 +167,12 @@ export interface CanvasLifecycleContext { host?: CanvasHostContext; } -/** Structured error returned from canvas handlers. */ +/** + * Structured error returned from canvas handlers. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. + */ export class CanvasError extends Error { constructor( public readonly code: string, @@ -140,6 +194,9 @@ export class CanvasError extends Error { /** * Options accepted by {@link createCanvas}. Combines the declarative * {@link CanvasDeclaration} fields with the in-process handler closures. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. */ export interface CanvasOptions { /** @see CanvasDeclaration.id */ @@ -175,6 +232,9 @@ export interface CanvasOptions { * ergonomics) where other SDKs (Rust, Python, Go, .NET) expose a single * `CanvasHandler` per session that switches on `canvasId`. Both shapes target * the same JSON-RPC wire protocol; the divergence is API ergonomics only. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. */ export class Canvas { readonly declaration: CanvasDeclaration; @@ -212,6 +272,9 @@ export class Canvas { * `DefineTool`'s co-location ergonomics) where other SDKs (Rust, Python, Go, * .NET) expose a single `CanvasHandler` per session that switches on * `canvasId`. Both shapes target the same JSON-RPC wire protocol. + * + * @experimental Part of an experimental wire-protocol surface; may change or + * be removed in future SDK or CLI releases. */ export function createCanvas(options: CanvasOptions): Canvas { return new Canvas(options); diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 42498c58f..31dd551ba 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -18,6 +18,7 @@ export { type CanvasAction, type CanvasActionContext, type CanvasDeclaration, + type CanvasHostCapabilities, type CanvasHostContext, type CanvasJsonSchema, type CanvasLifecycleContext, diff --git a/python/copilot/canvas.py b/python/copilot/canvas.py index 58c5b297d..500316a5d 100644 --- a/python/copilot/canvas.py +++ b/python/copilot/canvas.py @@ -7,6 +7,12 @@ :class:`CanvasHandler`; multiplexing across multiple declared canvases is the implementor's responsibility (e.g. by switching on :attr:`CanvasOpenContext.canvas_id`). + +.. note:: + + **Experimental.** All exports in this module are part of an experimental + wire-protocol surface and may change or be removed in future SDK or CLI + releases. """ from __future__ import annotations @@ -33,6 +39,7 @@ ] +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class ExtensionInfo: """Stable extension identity for session participants that provide canvases. @@ -50,6 +57,7 @@ def to_dict(self) -> dict[str, Any]: return {"source": self.source, "name": self.name} +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasDeclaration: """Declarative metadata for a single canvas, sent on @@ -84,6 +92,7 @@ def to_dict(self) -> dict[str, Any]: return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasOpenResponse: """Response returned from :meth:`CanvasHandler.on_open`.""" @@ -108,6 +117,7 @@ def to_dict(self) -> dict[str, Any]: return result +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasHostCapabilities: """Host capability details passed to canvas provider callbacks.""" @@ -122,6 +132,7 @@ def from_dict(obj: Any) -> CanvasHostCapabilities: return CanvasHostCapabilities(canvases=bool(obj.get("canvases", False))) +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasHostContext: """Host capabilities passed to canvas provider callbacks.""" @@ -138,6 +149,7 @@ def from_dict(obj: Any) -> CanvasHostContext: ) +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasOpenContext: """Context handed to :meth:`CanvasHandler.on_open`.""" @@ -161,6 +173,7 @@ class CanvasOpenContext: """Host capabilities supplied by the runtime.""" +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasActionContext: """Context handed to :meth:`CanvasHandler.on_action`.""" @@ -187,6 +200,7 @@ class CanvasActionContext: """Host capabilities supplied by the runtime.""" +# Experimental: this type is part of an experimental API and may change or be removed. @dataclass class CanvasLifecycleContext: """Context handed to a canvas's close lifecycle hook.""" @@ -207,6 +221,7 @@ class CanvasLifecycleContext: """Host capabilities supplied by the runtime.""" +# Experimental: this type is part of an experimental API and may change or be removed. class CanvasError(Exception): """Structured error returned from canvas handlers. @@ -241,6 +256,7 @@ def handler_unset(cls) -> CanvasError: ) +# Experimental: this type is part of an experimental API and may change or be removed. class CanvasHandler(ABC): """Provider-side canvas lifecycle handler. diff --git a/rust/src/canvas.rs b/rust/src/canvas.rs index ba13742ff..4bf692050 100644 --- a/rust/src/canvas.rs +++ b/rust/src/canvas.rs @@ -9,11 +9,25 @@ use crate::generated::api_types::CanvasAction; use crate::types::SessionId; /// JSON Schema object used for canvas inputs and canvas-scoped tools. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
pub type CanvasJsonSchema = serde_json::Map; /// Declarative metadata for a single canvas, sent over the wire on /// `session.create` / `session.resume`. -#[derive(Debug, Clone, Serialize, Deserialize)] +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct CanvasDeclaration { @@ -55,6 +69,13 @@ impl CanvasDeclaration { } /// Response returned from [`CanvasHandler::on_open`]. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct CanvasOpenResponse { @@ -70,6 +91,13 @@ pub struct CanvasOpenResponse { } /// Host capabilities passed to canvas provider callbacks. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
#[derive(Debug, Clone, Default, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CanvasHostContext { @@ -79,6 +107,13 @@ pub struct CanvasHostContext { } /// Host capability details passed to canvas provider callbacks. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
#[derive(Debug, Clone, Default, Deserialize)] #[serde(rename_all = "camelCase")] pub struct CanvasHostCapabilities { @@ -88,7 +123,14 @@ pub struct CanvasHostCapabilities { } /// Context handed to [`CanvasHandler::on_open`]. -#[derive(Debug, Clone)] +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default)] pub struct CanvasOpenContext { /// Session that requested the canvas. pub session_id: SessionId, @@ -105,7 +147,14 @@ pub struct CanvasOpenContext { } /// Context handed to [`CanvasHandler::on_action`]. -#[derive(Debug, Clone)] +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default)] pub struct CanvasActionContext { /// Session that invoked the action. pub session_id: SessionId, @@ -124,7 +173,14 @@ pub struct CanvasActionContext { } /// Context handed to a canvas's close lifecycle hook. -#[derive(Debug, Clone)] +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
+#[derive(Debug, Clone, Default)] pub struct CanvasLifecycleContext { /// Session owning the canvas instance. pub session_id: SessionId, @@ -139,6 +195,13 @@ pub struct CanvasLifecycleContext { } /// Structured error returned from canvas handlers. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
#[derive(Debug, Clone, Error, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "camelCase")] #[error("{code}: {message}")] @@ -168,6 +231,13 @@ impl CanvasError { } /// Result alias for canvas handler methods. +/// +///
+/// +/// **Experimental.** This type is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
pub type CanvasResult = Result; /// Provider-side canvas lifecycle handler. @@ -181,6 +251,13 @@ pub type CanvasResult = Result; /// /// The SDK does not maintain a per-canvas registry; multiplexing across /// declared canvases is the implementor's responsibility. +/// +///
+/// +/// **Experimental.** This trait is part of an experimental wire-protocol surface +/// and may change or be removed in future SDK or CLI releases. +/// +///
#[async_trait] pub trait CanvasHandler: Send + Sync { /// Open a new canvas instance.