/*---------------------------------------------------------------------------------------------
* 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;
using GitHub.Copilot.Rpc;
namespace GitHub.Copilot;
///
/// Declarative metadata for a single canvas, sent over the wire on
/// session.create / session.resume.
///
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasDeclaration
{
/// Canvas identifier, unique within the declaring connection.
[JsonPropertyName("id")]
public string Id { get; set; } = string.Empty;
/// Human-readable name shown in host UI and canvas pickers.
[JsonPropertyName("displayName")]
public string DisplayName { get; set; } = string.Empty;
/// Short, single-sentence description shown to the agent in canvas catalogs.
[JsonPropertyName("description")]
public string Description { get; set; } = string.Empty;
/// JSON Schema for the input payload accepted by canvas.open.
[JsonPropertyName("inputSchema")]
public JsonElement? InputSchema { get; set; }
/// Agent-callable actions this canvas exposes.
[JsonPropertyName("actions")]
public IList? Actions { get; set; }
}
///
/// Stable extension identity for session participants that provide canvases.
///
[Experimental(Diagnostics.Experimental)]
public sealed class ExtensionInfo
{
/// Extension namespace/source, e.g. "github-app".
[JsonPropertyName("source")]
public string Source { get; set; } = string.Empty;
/// Stable provider name within the source namespace.
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
}
/// Structured exception returned from canvas handlers.
///
/// Throw this from implementations to surface a
/// machine-readable error code to the runtime. Any other exception is wrapped
/// in a generic canvas_handler_error envelope.
///
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasException : Exception
{
/// Initializes a new .
/// Machine-readable error code.
/// Human-readable message.
public CanvasException(string code, string message) : base(message)
{
Code = code;
}
/// Machine-readable error code.
public string Code { get; }
///
/// Default exception returned when a custom action has no handler.
///
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
/// (and other handler-thrown exceptions) into structured JSON-RPC error responses.
///
internal static class CanvasErrorHelpers
{
private const int InternalError = -32603;
public static LocalRpcInvocationException HandlerUnset() => Build(
"canvas_handler_unset",
"No canvas handler is registered on this session");
public static LocalRpcInvocationException HandlerError(string message) => Build(
"canvas_handler_error",
message);
public static LocalRpcInvocationException ToRpcException(CanvasException error) => Build(error.Code, error.Message);
private static LocalRpcInvocationException Build(string code, string message)
{
JsonElement payload = JsonSerializer.SerializeToElement(
new JsonObject { ["code"] = code, ["message"] = message },
TypesJsonContext.Default.JsonObject);
return new LocalRpcInvocationException(InternalError, message, payload);
}
}
///
/// Provider-side canvas lifecycle handler.
///
///
/// A session installs a single via
/// SessionConfigBase.CanvasHandler. The handler receives every
/// inbound canvas.open / canvas.close / canvas.action.invoke
/// JSON-RPC request the runtime issues for this session and decides — typically
/// by inspecting — which
/// application-side canvas should handle the call.
///
/// The SDK does not maintain a per-canvas registry; multiplexing across
/// declared canvases is the implementor's responsibility.
///
///
/// Implementations targeting netstandard2.0 cannot rely on default
/// interface methods; derive from to inherit
/// sensible defaults for and .
///
///
[Experimental(Diagnostics.Experimental)]
public interface ICanvasHandler
{
/// Open a new canvas instance.
Task OnOpenAsync(CanvasProviderOpenRequest context, CancellationToken cancellationToken);
/// Canvas was closed by the user or agent. Default: no-op.
Task OnCloseAsync(CanvasProviderCloseRequest context, CancellationToken cancellationToken);
///
/// Handle a non-lifecycle action declared by the canvas.
/// Default: throws .
///
Task