diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln index f8e2e57a9916..ab7a07464c52 100644 --- a/dotnet/AutoGen.sln +++ b/dotnet/AutoGen.sln @@ -116,6 +116,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloAgent", "samples\Hello EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hello", "Hello", "{F42F9C8E-7BD9-4687-9B63-AFFA461AF5C1}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Grpc", "src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj", "{3D83C6DB-ACEA-48F3-959F-145CCD2EE135}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -294,6 +296,12 @@ Global {70A8D4B5-D0A6-4098-A6F3-6ED274B65E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU {70A8D4B5-D0A6-4098-A6F3-6ED274B65E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {70A8D4B5-D0A6-4098-A6F3-6ED274B65E7D}.Release|Any CPU.Build.0 = Release|Any CPU + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135}.CoreOnly|Any CPU.ActiveCfg = Debug|Any CPU + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135}.CoreOnly|Any CPU.Build.0 = Debug|Any CPU + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135}.Release|Any CPU.Build.0 = Release|Any CPU {AAD593FE-A49B-425E-A9FE-A0022CD25E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {AAD593FE-A49B-425E-A9FE-A0022CD25E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU {AAD593FE-A49B-425E-A9FE-A0022CD25E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU @@ -348,6 +356,7 @@ Global {EAFFE339-26CB-4019-991D-BCCE8E7D33A1} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64} {58AD8E1D-83BD-4950-A324-1A20677D78D9} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64} {70A8D4B5-D0A6-4098-A6F3-6ED274B65E7D} = {CE0AA8D5-12B8-4628-9589-DAD8CB0DDCF6} + {3D83C6DB-ACEA-48F3-959F-145CCD2EE135} = {18BF8DD7-0585-48BF-8F97-AD333080CE06} {AAD593FE-A49B-425E-A9FE-A0022CD25E3D} = {F42F9C8E-7BD9-4687-9B63-AFFA461AF5C1} {F42F9C8E-7BD9-4687-9B63-AFFA461AF5C1} = {CE0AA8D5-12B8-4628-9589-DAD8CB0DDCF6} EndGlobalSection diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs deleted file mode 100644 index af7488209e22..000000000000 --- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// App.cs -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using Google.Protobuf; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; - -namespace Microsoft.AutoGen.Core.Grpc; - -public static class AgentsApp -{ - // need a variable to store the runtime instance - public static IHost? Host { get; private set; } - - [MemberNotNull(nameof(Host))] - public static async ValueTask StartAsync(HostApplicationBuilder? builder = null, AgentTypes? agentTypes = null, bool local = false) - { - builder ??= new HostApplicationBuilder(); - builder.Services.TryAddSingleton(DistributedContextPropagator.Current); - if (!local) - { - builder.AddGrpcAgentWorker() - .AddAgents(agentTypes); - } - else - { - builder.AddAgentWorker() - .AddAgents(agentTypes); - } - var app = builder.Build(); - Host = app; - await app.StartAsync().ConfigureAwait(false); - return Host; - } - public static async ValueTask PublishMessageAsync( - string topic, - IMessage message, - HostApplicationBuilder? builder = null, - AgentTypes? agents = null, - bool local = false) - { - if (Host == null) - { - await StartAsync(builder, agents, local); - } - var client = Host.Services.GetRequiredService() ?? throw new InvalidOperationException("Host not started"); - await client.PublishMessageAsync(message, topic, token: new CancellationToken()).ConfigureAwait(true); - return Host; - } - public static async ValueTask ShutdownAsync() - { - if (Host == null) - { - throw new InvalidOperationException("Host not started"); - } - await Host.StopAsync(); - } - - private static IHostApplicationBuilder AddAgents(this IHostApplicationBuilder builder, AgentTypes? agentTypes) - { - agentTypes ??= AgentTypes.GetAgentTypesFromAssembly() - ?? throw new InvalidOperationException("No agent types found in the assembly"); - foreach (var type in agentTypes.Types) - { - builder.AddAgent(type.Key, type.Value); - } - return builder; - } -} diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentRuntime.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentRuntime.cs deleted file mode 100644 index 1a505be6c3b7..000000000000 --- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentRuntime.cs +++ /dev/null @@ -1,463 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// GrpcAgentRuntime.cs - -using System.Collections.Concurrent; -using System.Reflection; -using System.Threading.Channels; -using Google.Protobuf; -using Grpc.Core; -using Microsoft.AutoGen.Contracts; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; - -namespace Microsoft.AutoGen.Core.Grpc; - -public sealed class GrpcAgentRuntime( - AgentRpc.AgentRpcClient client, - IHostApplicationLifetime hostApplicationLifetime, - IServiceProvider serviceProvider, - [FromKeyedServices("AgentTypes")] IEnumerable> configuredAgentTypes, - ILogger logger - ) : AgentRuntime( - hostApplicationLifetime, - serviceProvider, - configuredAgentTypes, - logger - ), IDisposable -{ - private readonly object _channelLock = new(); - private readonly ConcurrentDictionary _agentTypes = new(); - private readonly ConcurrentDictionary<(string Type, string Key), Agent> _agents = new(); - private readonly ConcurrentDictionary _pendingRequests = new(); - private readonly ConcurrentDictionary> _agentsForEvent = new(); - private readonly Channel<(Message Message, TaskCompletionSource WriteCompletionSource)> _outboundMessagesChannel = Channel.CreateBounded<(Message, TaskCompletionSource)>(new BoundedChannelOptions(1024) - { - AllowSynchronousContinuations = true, - SingleReader = true, - SingleWriter = false, - FullMode = BoundedChannelFullMode.Wait - }); - private readonly AgentRpc.AgentRpcClient _client = client; - public readonly IServiceProvider ServiceProvider = serviceProvider; - private readonly IEnumerable> _configuredAgentTypes = configuredAgentTypes; - private new readonly ILogger _logger = logger; - private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping); - private AsyncDuplexStreamingCall? _channel; - private Task? _readTask; - private Task? _writeTask; - public void Dispose() - { - _outboundMessagesChannel.Writer.TryComplete(); - _channel?.Dispose(); - } - private async Task RunReadPump() - { - var channel = GetChannel(); - while (!_shutdownCts.Token.IsCancellationRequested) - { - try - { - await foreach (var message in channel.ResponseStream.ReadAllAsync(_shutdownCts.Token)) - { - // next if message is null - if (message == null) - { - continue; - } - switch (message.MessageCase) - { - case Message.MessageOneofCase.Request: - GetOrActivateAgent(message.Request.Target).ReceiveMessage(message); - break; - case Message.MessageOneofCase.Response: - if (!_pendingRequests.TryRemove(message.Response.RequestId, out var request)) - { - throw new InvalidOperationException($"Unexpected response '{message.Response}'"); - } - - message.Response.RequestId = request.OriginalRequestId; - request.Agent.ReceiveMessage(message); - break; - case Message.MessageOneofCase.RegisterAgentTypeResponse: - if (!message.RegisterAgentTypeResponse.Success) - { - _logger.LogError($"Failed to register agent type '{message.RegisterAgentTypeResponse.Error}'"); - } - break; - case Message.MessageOneofCase.AddSubscriptionResponse: - if (!message.AddSubscriptionResponse.Success) - { - _logger.LogError($"Failed to add subscription '{message.AddSubscriptionResponse.Error}'"); - } - break; - case Message.MessageOneofCase.CloudEvent: - var item = message.CloudEvent; - if (!_agentsForEvent.TryGetValue(item.Type, out var agents)) - { - _logger.LogError($"This worker can't handle the event type '{item.Type}'."); - break; - } - foreach (var a in agents) - { - var subject = item.GetSubject(); - if (string.IsNullOrEmpty(subject)) - { - subject = item.Source; - } - var agent = GetOrActivateAgent(new AgentId { Type = a.Name, Key = subject }); - agent.ReceiveMessage(message); - } - break; - default: - throw new InvalidOperationException($"Unexpected message '{message}'."); - } - } - } - catch (OperationCanceledException) - { - // Time to shut down. - break; - } - catch (Exception ex) when (!_shutdownCts.IsCancellationRequested) - { - _logger.LogError(ex, "Error reading from channel."); - channel = RecreateChannel(channel); - } - catch - { - // Shutdown requested. - break; - } - } - } - private async Task RunWritePump() - { - var channel = GetChannel(); - var outboundMessages = _outboundMessagesChannel.Reader; - while (!_shutdownCts.IsCancellationRequested) - { - (Message Message, TaskCompletionSource WriteCompletionSource) item = default; - try - { - await outboundMessages.WaitToReadAsync().ConfigureAwait(false); - - // Read the next message if we don't already have an unsent message - // waiting to be sent. - if (!outboundMessages.TryRead(out item)) - { - break; - } - - while (!_shutdownCts.IsCancellationRequested) - { - await channel.RequestStream.WriteAsync(item.Message, _shutdownCts.Token).ConfigureAwait(false); - item.WriteCompletionSource.TrySetResult(); - break; - } - } - catch (OperationCanceledException) - { - // Time to shut down. - item.WriteCompletionSource?.TrySetCanceled(); - break; - } - catch (RpcException ex) when (ex.StatusCode == StatusCode.Unavailable) - { - // we could not connect to the endpoint - most likely we have the wrong port or failed ssl - // we need to let the user know what port we tried to connect to and then do backoff and retry - _logger.LogError(ex, "Error connecting to GRPC endpoint {Endpoint}.", Environment.GetEnvironmentVariable("AGENT_HOST")); - break; - } - catch (RpcException ex) when (ex.StatusCode == StatusCode.OK) - { - _logger.LogError(ex, "Error writing to channel, continuing (Status OK). {ex}", channel.ToString()); - break; - } - catch (Exception ex) when (!_shutdownCts.IsCancellationRequested) - { - item.WriteCompletionSource?.TrySetException(ex); - _logger.LogError(ex, $"Error writing to channel.{ex}"); - channel = RecreateChannel(channel); - continue; - } - catch - { - // Shutdown requested. - item.WriteCompletionSource?.TrySetCanceled(); - break; - } - } - - while (outboundMessages.TryRead(out var item)) - { - item.WriteCompletionSource.TrySetCanceled(); - } - } - private new Agent GetOrActivateAgent(AgentId agentId) - { - if (!_agents.TryGetValue((agentId.Type, agentId.Key), out var agent)) - { - if (_agentTypes.TryGetValue(agentId.Type, out var agentType)) - { - agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType); - Agent.Initialize(this, agent); - _agents.TryAdd((agentId.Type, agentId.Key), agent); - } - else - { - throw new InvalidOperationException($"Agent type '{agentId.Type}' is unknown."); - } - } - - return agent; - } - - private async ValueTask RegisterAgentTypeAsync(string type, Type agentType, CancellationToken cancellationToken = default) - { - if (_agentTypes.TryAdd(type, agentType)) - { - var events = agentType.GetInterfaces() - .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandle<>)) - .Select(i => ReflectionHelper.GetMessageDescriptor(i.GetGenericArguments().First())?.FullName); - // add the agentType to the list of agent types that handle the event - foreach (var evt in events) - { - if (!_agentsForEvent.TryGetValue(evt!, out var agents)) - { - agents = new HashSet(); - _agentsForEvent[evt!] = agents; - } - - agents.Add(agentType); - } - var topicTypes = agentType.GetCustomAttributes().Select(t => t.Topic).ToList(); - /* var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest - { - Type = type, - Topics = { topicTypes }, - Events = { events } - }, null, null, cancellationToken); */ - await WriteChannelAsync(new Message - { - RegisterAgentTypeRequest = new RegisterAgentTypeRequest - { - RequestId = Guid.NewGuid().ToString(), - Type = type, - //Topics = { topicTypes }, //future - //Events = { events } //future - } - }, cancellationToken).ConfigureAwait(false); - if (!topicTypes.Any()) - { - topicTypes.Add(agentType.Name); - } - foreach (var topic in topicTypes) - { - var subscriptionRequest = new Message - { - AddSubscriptionRequest = new AddSubscriptionRequest - { - RequestId = Guid.NewGuid().ToString(), - Subscription = new Subscription - { - TypeSubscription = new TypeSubscription - { - AgentType = type, - TopicType = topic - } - } - } - }; - await _client.AddSubscriptionAsync(subscriptionRequest.AddSubscriptionRequest, null, null, cancellationToken); - foreach (var e in events) - { - subscriptionRequest = new Message - { - AddSubscriptionRequest = new AddSubscriptionRequest - { - RequestId = Guid.NewGuid().ToString(), - Subscription = new Subscription - { - TypeSubscription = new TypeSubscription - { - AgentType = type, - TopicType = topic + "." + e - } - } - } - }; - await _client.AddSubscriptionAsync(subscriptionRequest.AddSubscriptionRequest, null, null, cancellationToken); - } - } - } - } - public override async ValueTask SendMessageAsync(IMessage message, AgentId agentId, AgentId? agent = null, CancellationToken? cancellationToken = default) - { - var request = new RpcRequest - { - RequestId = Guid.NewGuid().ToString(), - Source = agent, - Target = agentId, - Payload = (Payload)message, - }; - var response = await InvokeRequestAsync(request).ConfigureAwait(false); - return response; - } - // new is intentional - public new async ValueTask RuntimeSendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default) - { - await WriteChannelAsync(new Message { Response = response }, cancellationToken).ConfigureAwait(false); - } - public new async ValueTask RuntimeSendRequestAsync(IAgent agent, RpcRequest request, CancellationToken cancellationToken = default) - { - var requestId = Guid.NewGuid().ToString(); - _pendingRequests[requestId] = ((Agent)agent, request.RequestId); - request.RequestId = requestId; - await WriteChannelAsync(new Message { Request = request }, cancellationToken).ConfigureAwait(false); - } - public new async ValueTask RuntimeWriteMessage(Message message, CancellationToken cancellationToken = default) - { - await WriteChannelAsync(message, cancellationToken).ConfigureAwait(false); - } - public async ValueTask RuntimePublishEventAsync(CloudEvent @event, CancellationToken cancellationToken = default) - { - await WriteChannelAsync(new Message { CloudEvent = @event }, cancellationToken).ConfigureAwait(false); - } - private async Task WriteChannelAsync(Message message, CancellationToken cancellationToken = default) - { - var tcs = new TaskCompletionSource(); - await _outboundMessagesChannel.Writer.WriteAsync((message, tcs), cancellationToken).ConfigureAwait(false); - } - private AsyncDuplexStreamingCall GetChannel() - { - if (_channel is { } channel) - { - return channel; - } - - lock (_channelLock) - { - if (_channel is not null) - { - return _channel; - } - - return RecreateChannel(null); - } - } - - private AsyncDuplexStreamingCall RecreateChannel(AsyncDuplexStreamingCall? channel) - { - if (_channel is null || _channel == channel) - { - lock (_channelLock) - { - if (_channel is null || _channel == channel) - { - _channel?.Dispose(); - _channel = _client.OpenChannel(cancellationToken: _shutdownCts.Token); - } - } - } - - return _channel; - } - public new async Task StartAsync(CancellationToken cancellationToken) - { - _channel = GetChannel(); - _logger.LogInformation("Starting " + GetType().Name + ",connecting to gRPC endpoint " + Environment.GetEnvironmentVariable("AGENT_HOST")); - - StartCore(); - - var tasks = new List(_agentTypes.Count); - foreach (var (typeName, type) in _configuredAgentTypes) - { - tasks.Add(RegisterAgentTypeAsync(typeName, type, cancellationToken).AsTask()); - } - - await Task.WhenAll(tasks).ConfigureAwait(true); - - void StartCore() - { - var didSuppress = false; - if (!ExecutionContext.IsFlowSuppressed()) - { - didSuppress = true; - ExecutionContext.SuppressFlow(); - } - - try - { - _readTask = Task.Run(RunReadPump, cancellationToken); - _writeTask = Task.Run(RunWritePump, cancellationToken); - } - finally - { - if (didSuppress) - { - ExecutionContext.RestoreFlow(); - } - } - } - } - public new async Task StopAsync(CancellationToken cancellationToken) - { - _shutdownCts.Cancel(); - - _outboundMessagesChannel.Writer.TryComplete(); - - if (_readTask is { } readTask) - { - await readTask.ConfigureAwait(false); - } - - if (_writeTask is { } writeTask) - { - await writeTask.ConfigureAwait(false); - } - lock (_channelLock) - { - _channel?.Dispose(); - } - } - public new async ValueTask SaveStateAsync(AgentState value, CancellationToken cancellationToken = default) - { - var agentId = value.AgentId ?? throw new InvalidOperationException("AgentId is required when saving AgentState."); - var response = _client.SaveState(value, null, null, cancellationToken); - if (!response.Success) - { - throw new InvalidOperationException($"Error saving AgentState for AgentId {agentId}."); - } - } - - public new async ValueTask LoadStateAsync(AgentId agentId, CancellationToken cancellationToken = default) - { - var response = await _client.GetStateAsync(agentId).ConfigureAwait(true); - // if (response.Success && response.AgentState.AgentId is not null) - why is success always false? - if (response.AgentState.AgentId is not null) - { - return response.AgentState; - } - else - { - throw new KeyNotFoundException($"Failed to read AgentState for {agentId}."); - } - } - public new async ValueTask> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default) - { - var response = await _client.GetSubscriptionsAsync(request, null, null, cancellationToken); - return response.Subscriptions.ToList(); - } - public new async Task AddSubscriptionAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default) - { - var response = _client.AddSubscription(request, null, null, cancellationToken); - return response; - } - public new async ValueTask RemoveSubscriptionAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default) - { - var response = _client.RemoveSubscription(request, null, null, cancellationToken); - return response; - } -} - diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs deleted file mode 100644 index 4e9e0bbca8bf..000000000000 --- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// GrpcAgentWorkerHostBuilderExtension.cs -using System.Diagnostics; -using System.Reflection; -using Google.Protobuf.Reflection; -using Grpc.Core; -using Grpc.Net.Client.Configuration; -using Microsoft.AutoGen.Contracts; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.DependencyInjection.Extensions; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -namespace Microsoft.AutoGen.Core.Grpc; - -public static class GrpcAgentWorkerHostBuilderExtensions -{ - private const string _defaultAgentServiceAddress = "https://localhost:53071"; - public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBuilder builder, string? agentServiceAddress = null) - { - builder.Services.AddGrpcClient(options => - { - options.Address = new Uri(agentServiceAddress ?? builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress); - options.ChannelOptionsActions.Add(channelOptions => - { - var loggerFactory = new LoggerFactory(); - if (Debugger.IsAttached) - { - channelOptions.HttpHandler = new SocketsHttpHandler - { - EnableMultipleHttp2Connections = false, - KeepAlivePingDelay = TimeSpan.FromSeconds(200), - KeepAlivePingTimeout = TimeSpan.FromSeconds(100), - KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always - }; - } - else - { - channelOptions.HttpHandler = new SocketsHttpHandler - { - EnableMultipleHttp2Connections = true, - KeepAlivePingDelay = TimeSpan.FromSeconds(20), - KeepAlivePingTimeout = TimeSpan.FromSeconds(10), - KeepAlivePingPolicy = HttpKeepAlivePingPolicy.WithActiveRequests - }; - } - - var methodConfig = new MethodConfig - { - Names = { MethodName.Default }, - RetryPolicy = new RetryPolicy - { - MaxAttempts = 5, - InitialBackoff = TimeSpan.FromSeconds(1), - MaxBackoff = TimeSpan.FromSeconds(5), - BackoffMultiplier = 1.5, - RetryableStatusCodes = { StatusCode.Unavailable } - } - }; - - channelOptions.ServiceConfig = new() { MethodConfigs = { methodConfig } }; - channelOptions.ThrowOperationCanceledOnCancellation = true; - }); - }); - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - builder.Services.TryAddSingleton(DistributedContextPropagator.Current); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(sp => (IHostedService)sp.GetRequiredService()); - builder.Services.AddKeyedSingleton("AgentsMetadata", (sp, key) => - { - return ReflectionHelper.GetAgentsMetadata(assemblies); - }); - builder.Services.AddSingleton((s) => - { - var worker = s.GetRequiredService(); - var client = ActivatorUtilities.CreateInstance(s); - Agent.Initialize(worker, client); - return client; - }); - builder.Services.AddSingleton(new AgentApplicationBuilder(builder)); - return builder; - } - private static MessageDescriptor? GetMessageDescriptor(Type type) - { - var property = type.GetProperty("Descriptor", BindingFlags.Static | BindingFlags.Public); - return property?.GetValue(null) as MessageDescriptor; - } -} diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj b/dotnet/src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj index 9ab2d7419faf..c28a9b1c9087 100644 --- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj +++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj @@ -9,7 +9,18 @@ - + + + + + + + + + + + + diff --git a/dotnet/src/Microsoft.AutoGen/Core/ResultSink.cs b/dotnet/src/Microsoft.AutoGen/Core/ResultSink.cs index 512a81b1fed6..d103bdfda621 100644 --- a/dotnet/src/Microsoft.AutoGen/Core/ResultSink.cs +++ b/dotnet/src/Microsoft.AutoGen/Core/ResultSink.cs @@ -14,7 +14,7 @@ internal interface IResultSink : IValueTaskSource ValueTask Future { get; } } -internal sealed class ResultSink : IResultSink +public sealed class ResultSink : IResultSink { private ManualResetValueTaskSourceCore core;