Skip to content
Merged
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
24 changes: 21 additions & 3 deletions src/A2A/Client/A2AClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public async Task<ListTaskPushNotificationConfigResponse> ListTaskPushNotificati
/// <inheritdoc />
public async Task DeleteTaskPushNotificationConfigAsync(DeleteTaskPushNotificationConfigRequest request, CancellationToken cancellationToken = default)
{
await SendJsonRpcRequestAsync<object>(A2AMethods.DeleteTaskPushNotificationConfig, request, cancellationToken).ConfigureAwait(false);
await SendJsonRpcRequestAsync(A2AMethods.DeleteTaskPushNotificationConfig, request, cancellationToken).ConfigureAwait(false);
}

/// <inheritdoc />
Expand All @@ -111,6 +111,25 @@ public void Dispose()
[UnconditionalSuppressMessage("AOT", "IL2026:RequiresUnreferencedCode", Justification = "All types are registered in source-generated JsonContext.")]
[UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "All types are registered in source-generated JsonContext.")]
private async Task<TResult> SendJsonRpcRequestAsync<TResult>(string method, object? @params, CancellationToken cancellationToken)
{
var rpcResponse = await SendJsonRpcRequestCoreAsync(method, @params, cancellationToken).ConfigureAwait(false);

return rpcResponse.Result.Deserialize<TResult>(A2AJsonUtilities.DefaultOptions)
?? throw new A2AException("Failed to deserialize JSON-RPC result.", A2AErrorCode.InternalError);
}

/// <summary>Sends a JSON-RPC request for methods whose successful response carries no result, e.g. a null <c>result</c> member.</summary>
/// <param name="method">The JSON-RPC method name.</param>
/// <param name="params">The request parameters to serialize, if any.</param>
/// <param name="cancellationToken">A token to cancel the operation.</param>
private async Task SendJsonRpcRequestAsync(string method, object? @params, CancellationToken cancellationToken)
{
_ = await SendJsonRpcRequestCoreAsync(method, @params, cancellationToken).ConfigureAwait(false);
}
Comment thread
darrelmiller marked this conversation as resolved.

[UnconditionalSuppressMessage("AOT", "IL2026:RequiresUnreferencedCode", Justification = "All types are registered in source-generated JsonContext.")]
[UnconditionalSuppressMessage("AOT", "IL3050:RequiresDynamicCode", Justification = "All types are registered in source-generated JsonContext.")]
private async Task<JsonRpcResponse> SendJsonRpcRequestCoreAsync(string method, object? @params, CancellationToken cancellationToken)
{
using var activity = A2ADiagnostics.Source.StartActivity($"A2AClient/{method}", ActivityKind.Client);
var stopwatch = Stopwatch.StartNew();
Expand Down Expand Up @@ -146,8 +165,7 @@ private async Task<TResult> SendJsonRpcRequestAsync<TResult>(string method, obje
throw new A2AException(error.Message, (A2AErrorCode)error.Code);
}

return rpcResponse.Result.Deserialize<TResult>(A2AJsonUtilities.DefaultOptions)
?? throw new A2AException("Failed to deserialize JSON-RPC result.", A2AErrorCode.InternalError);
return rpcResponse;
}
catch (Exception ex)
{
Expand Down
10 changes: 10 additions & 0 deletions tests/A2A.UnitTests/Client/A2AClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,16 @@ public async Task DeletePushNotificationConfigAsync_SendsCorrectMethod()
Assert.Equal(A2AMethods.DeleteTaskPushNotificationConfig, requestJson.RootElement.GetProperty("method").GetString());
}

[Fact]
public async Task DeletePushNotificationConfigAsync_CompletesOnNullResult()
{
// A2AJsonRpcProcessor answers delete with a success response whose result is null,
// which is valid per JSON-RPC 2.0 for the only void-result A2A method.
var sut = CreateA2AClient(new JsonRpcResponse { Id = "test-id", Result = null });

await sut.DeleteTaskPushNotificationConfigAsync(new DeleteTaskPushNotificationConfigRequest { Id = "cfg-1", TaskId = "t-1" });
}

private static A2AClient CreateA2AClient(object result, Action<HttpRequestMessage>? onRequest = null, bool isSse = false)
{
var response = new JsonRpcResponse
Expand Down
Loading