Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 8 additions & 112 deletions dotnet/src/Canvas.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,110 +55,6 @@ public sealed class ExtensionInfo
public string Name { get; set; } = string.Empty;
}

/// <summary>Response returned from <see cref="ICanvasHandler.OnOpenAsync"/>.</summary>
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasOpenResponse
{
/// <summary>URL the host should render. Optional for canvases with no visual surface.</summary>
[JsonPropertyName("url")]
public string? Url { get; set; }

/// <summary>Provider-supplied title shown in host chrome.</summary>
[JsonPropertyName("title")]
public string? Title { get; set; }

/// <summary>Provider-supplied status text shown in host chrome.</summary>
[JsonPropertyName("status")]
public string? Status { get; set; }
}

/// <summary>Host capabilities passed to canvas provider callbacks.</summary>
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasHostContext
{
/// <summary>Host capability details.</summary>
[JsonPropertyName("capabilities")]
public CanvasHostCapabilities Capabilities { get; set; } = new();
}

/// <summary>Host capability details passed to canvas provider callbacks.</summary>
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasHostCapabilities
{
/// <summary>Whether the host supports canvas rendering.</summary>
[JsonPropertyName("canvases")]
public bool Canvases { get; set; }
}

/// <summary>Context handed to <see cref="ICanvasHandler.OnOpenAsync"/>.</summary>
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasOpenContext
{
/// <summary>Session that requested the canvas.</summary>
public string SessionId { get; init; } = string.Empty;

/// <summary>Owning provider identifier.</summary>
public string ExtensionId { get; init; } = string.Empty;

/// <summary>Canvas id from the declaring <see cref="CanvasDeclaration"/>.</summary>
public string CanvasId { get; init; } = string.Empty;

/// <summary>Stable instance id supplied by the runtime.</summary>
public string InstanceId { get; init; } = string.Empty;

/// <summary>Validated input payload.</summary>
public JsonElement Input { get; init; }

/// <summary>Host capabilities supplied by the runtime.</summary>
public CanvasHostContext? Host { get; init; }
}

/// <summary>Context handed to <see cref="ICanvasHandler.OnActionAsync"/>.</summary>
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasActionContext
{
/// <summary>Session that invoked the action.</summary>
public string SessionId { get; init; } = string.Empty;

/// <summary>Owning provider identifier.</summary>
public string ExtensionId { get; init; } = string.Empty;

/// <summary>Canvas id targeted by the action.</summary>
public string CanvasId { get; init; } = string.Empty;

/// <summary>Instance id targeted by the action.</summary>
public string InstanceId { get; init; } = string.Empty;

/// <summary>Action name from <see cref="CanvasAction.Name"/>.</summary>
public string ActionName { get; init; } = string.Empty;

/// <summary>Validated input payload.</summary>
public JsonElement Input { get; init; }

/// <summary>Host capabilities supplied by the runtime.</summary>
public CanvasHostContext? Host { get; init; }
}

/// <summary>Context handed to a canvas's close lifecycle hook.</summary>
[Experimental(Diagnostics.Experimental)]
public sealed class CanvasLifecycleContext
{
/// <summary>Session owning the canvas instance.</summary>
public string SessionId { get; init; } = string.Empty;

/// <summary>Owning provider identifier.</summary>
public string ExtensionId { get; init; } = string.Empty;

/// <summary>Canvas id from the declaring <see cref="CanvasDeclaration"/>.</summary>
public string CanvasId { get; init; } = string.Empty;

/// <summary>Instance id this lifecycle event applies to.</summary>
public string InstanceId { get; init; } = string.Empty;

/// <summary>Host capabilities supplied by the runtime.</summary>
public CanvasHostContext? Host { get; init; }
}

/// <summary>Structured error returned from canvas handlers.</summary>
/// <remarks>
/// Throw this from <see cref="ICanvasHandler"/> implementations to surface a
Expand Down Expand Up @@ -234,9 +130,9 @@ internal partial class CanvasJsonContext : JsonSerializerContext;
/// <remarks>
/// A session installs a single <see cref="ICanvasHandler"/> via
/// <c>SessionConfigBase.CanvasHandler</c>. The handler receives every
/// inbound <c>canvas.open</c> / <c>canvas.close</c> / <c>canvas.action.invoke</c>
/// inbound <c>canvas.open</c> / <c>canvas.close</c> / <c>canvas.invokeAction</c>
/// JSON-RPC request the runtime issues for this session and decides — typically
/// by inspecting <see cref="CanvasOpenContext.CanvasId"/> — which
/// by inspecting <see cref="CanvasProviderOpenRequest.CanvasId"/> — which
/// application-side canvas should handle the call.
/// <para>
/// The SDK does not maintain a per-canvas registry; multiplexing across
Expand All @@ -252,16 +148,16 @@ internal partial class CanvasJsonContext : JsonSerializerContext;
public interface ICanvasHandler
{
/// <summary>Open a new canvas instance.</summary>
Task<CanvasOpenResponse> OnOpenAsync(CanvasOpenContext context, CancellationToken cancellationToken);
Task<CanvasProviderOpenResult> OnOpenAsync(CanvasProviderOpenRequest context, CancellationToken cancellationToken);
Comment thread
SteveSandersonMS marked this conversation as resolved.
Comment thread
SteveSandersonMS marked this conversation as resolved.

/// <summary>Canvas was closed by the user or agent. Default: no-op.</summary>
Task OnCloseAsync(CanvasLifecycleContext context, CancellationToken cancellationToken);
Task OnCloseAsync(CanvasProviderCloseRequest context, CancellationToken cancellationToken);

/// <summary>
/// Handle a non-lifecycle action declared by the canvas.
/// Default: throws <see cref="CanvasError.NoHandler"/>.
/// </summary>
Task<object?> OnActionAsync(CanvasActionContext context, CancellationToken cancellationToken);
Task<object?> OnActionAsync(CanvasProviderInvokeActionRequest context, CancellationToken cancellationToken);
}

/// <summary>
Expand All @@ -272,17 +168,17 @@ public interface ICanvasHandler
public abstract class CanvasHandlerBase : ICanvasHandler
{
/// <inheritdoc />
public abstract Task<CanvasOpenResponse> OnOpenAsync(CanvasOpenContext context, CancellationToken cancellationToken);
public abstract Task<CanvasProviderOpenResult> OnOpenAsync(CanvasProviderOpenRequest context, CancellationToken cancellationToken);

/// <inheritdoc />
public virtual Task OnCloseAsync(CanvasLifecycleContext context, CancellationToken cancellationToken)
public virtual Task OnCloseAsync(CanvasProviderCloseRequest context, CancellationToken cancellationToken)
#if NET8_0_OR_GREATER
=> Task.CompletedTask;
#else
=> Task.FromResult<object?>(null);
#endif

/// <inheritdoc />
public virtual Task<object?> OnActionAsync(CanvasActionContext context, CancellationToken cancellationToken)
public virtual Task<object?> OnActionAsync(CanvasProviderInvokeActionRequest context, CancellationToken cancellationToken)
=> Task.FromException<object?>(CanvasError.NoHandler());
}
43 changes: 0 additions & 43 deletions dotnet/src/Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1625,9 +1625,6 @@ private async Task<Connection> ConnectToServerAsync(Process? cliProcess, string?
rpc.SetLocalRpcMethod("autoModeSwitch.request", handler.OnAutoModeSwitchRequest);
rpc.SetLocalRpcMethod("hooks.invoke", handler.OnHooksInvoke);
rpc.SetLocalRpcMethod("systemMessage.transform", handler.OnSystemMessageTransform);
rpc.SetLocalRpcMethod("canvas.open", handler.OnCanvasOpen);
rpc.SetLocalRpcMethod("canvas.close", handler.OnCanvasClose);
rpc.SetLocalRpcMethod("canvas.action.invoke", handler.OnCanvasInvokeAction);
ClientSessionApiRegistration.RegisterClientSessionApiHandlers(rpc, sessionId =>
{
var session = GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
Expand Down Expand Up @@ -1821,46 +1818,6 @@ public async ValueTask<SystemMessageTransformRpcResponse> OnSystemMessageTransfo
return await session.HandleSystemMessageTransformAsync(sections);
}

#pragma warning disable GHCP001
public ValueTask<CanvasOpenResponse> OnCanvasOpen(
string sessionId,
string extensionId,
string canvasId,
string instanceId,
JsonElement? input = null,
CanvasHostContext? host = null)
{
var session = client.GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
return session.HandleCanvasOpenAsync(
extensionId, canvasId, instanceId, input ?? default, host);
}

public async ValueTask OnCanvasClose(
string sessionId,
string extensionId,
string canvasId,
string instanceId,
JsonElement? input = null,
CanvasHostContext? host = null)
{
var session = client.GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
await session.HandleCanvasCloseAsync(extensionId, canvasId, instanceId, host);
}

public ValueTask<JsonElement> OnCanvasInvokeAction(
string sessionId,
string extensionId,
string canvasId,
string instanceId,
string actionName,
JsonElement? input = null,
CanvasHostContext? host = null)
{
var session = client.GetSession(sessionId) ?? throw new ArgumentException($"Unknown session {sessionId}");
return session.HandleCanvasActionAsync(
extensionId, canvasId, instanceId, actionName, input ?? default, host);
}
#pragma warning restore GHCP001
}

private class Connection(
Expand Down
Loading
Loading