diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index c1b26f2f9..5321860e4 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -4,26 +4,25 @@
1.22.0
1.22.0-alpha
9.0.0-preview.9.24525.1
-
direct
-
+
-
-
-
+
+
+
-
-
+
+
-
+
-
+
-
+
@@ -43,25 +42,25 @@
-
+
-
+
-
-
-
-
+
+
+
+
-
+
runtime; build; native; contentfiles; analyzers; buildtransitive
@@ -78,17 +77,17 @@
-
+
-
+
-
-
+
+
@@ -96,28 +95,29 @@
-
-
+
+
-
-
+
+
-
+
-
+
-
+
+
-
+
-
+
\ No newline at end of file
diff --git a/dotnet/global.json b/dotnet/global.json
index 5f78cce06..4f9e9b79a 100644
--- a/dotnet/global.json
+++ b/dotnet/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "8.0.104",
+ "version": "8.0.401",
"rollForward": "latestMinor"
}
}
diff --git a/dotnet/samples/Hello/Backend/Backend.csproj b/dotnet/samples/Hello/Backend/Backend.csproj
index d502d7260..360459334 100644
--- a/dotnet/samples/Hello/Backend/Backend.csproj
+++ b/dotnet/samples/Hello/Backend/Backend.csproj
@@ -1,4 +1,4 @@
-
+
diff --git a/dotnet/samples/Hello/Backend/Program.cs b/dotnet/samples/Hello/Backend/Program.cs
index b913d39d6..b74dba139 100644
--- a/dotnet/samples/Hello/Backend/Program.cs
+++ b/dotnet/samples/Hello/Backend/Program.cs
@@ -1,7 +1,5 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Program.cs
-using Microsoft.Extensions.Hosting;
-
var app = await Microsoft.AutoGen.Agents.Host.StartAsync(local: false, useGrpc: true);
await app.WaitForShutdownAsync();
diff --git a/dotnet/samples/Hello/Backend/appsettings.json b/dotnet/samples/Hello/Backend/appsettings.json
index 3bb8d8825..ae32fe371 100644
--- a/dotnet/samples/Hello/Backend/appsettings.json
+++ b/dotnet/samples/Hello/Backend/appsettings.json
@@ -1,9 +1,15 @@
{
- "Logging": {
- "LogLevel": {
- "Default": "Warning",
- "Microsoft": "Warning",
- "Microsoft.Orleans": "Warning"
- }
+ "Logging": {
+ "LogLevel": {
+ "Default": "Warning",
+ "Microsoft": "Warning",
+ "Microsoft.Orleans": "Warning"
}
- }
\ No newline at end of file
+ },
+ "AllowedHosts": "*",
+ "Kestrel": {
+ "EndpointDefaults": {
+ "Protocols": "Http2"
+ }
+ }
+}
diff --git a/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj b/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj
index 88d23268c..5ce0d0531 100644
--- a/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj
+++ b/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj
@@ -1,7 +1,10 @@
+
+
+
Exe
- net8.0
+ net8.0
enable
enable
true
diff --git a/dotnet/samples/Hello/Hello.AppHost/Program.cs b/dotnet/samples/Hello/Hello.AppHost/Program.cs
index d9acc3ea3..326eddbcc 100644
--- a/dotnet/samples/Hello/Hello.AppHost/Program.cs
+++ b/dotnet/samples/Hello/Hello.AppHost/Program.cs
@@ -1,7 +1,19 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Program.cs
+using Microsoft.Extensions.Hosting;
+
var builder = DistributedApplication.CreateBuilder(args);
-var backend = builder.AddProject("backend");
-builder.AddProject("client").WithReference(backend).WaitFor(backend);
-builder.Build().Run();
+var backend = builder.AddProject("backend").WithExternalHttpEndpoints();
+builder.AddProject("client")
+ .WithReference(backend)
+ .WithEnvironment("AGENT_HOST", $"{backend.GetEndpoint("https").Property(EndpointProperty.Url)}")
+ .WaitFor(backend);
+
+using var app = builder.Build();
+
+await app.StartAsync();
+var url = backend.GetEndpoint("http").Url;
+Console.WriteLine("Backend URL: " + url);
+
+await app.WaitForShutdownAsync();
diff --git a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj
index f17ab0c9f..e49cfd456 100644
--- a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj
+++ b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj
@@ -1,7 +1,7 @@
Exe
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj b/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj
index 88893ccc8..dcb693a52 100644
--- a/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj
+++ b/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj
@@ -1,7 +1,7 @@
Exe
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/samples/Hello/HelloAgent/Program.cs b/dotnet/samples/Hello/HelloAgent/Program.cs
index 506d91502..4f74520a7 100644
--- a/dotnet/samples/Hello/HelloAgent/Program.cs
+++ b/dotnet/samples/Hello/HelloAgent/Program.cs
@@ -19,7 +19,7 @@ var app = await AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageRecei
{
Message = "World"
}, local: true);
-
+//var app = await AgentsApp.StartAsync();
await app.WaitForShutdownAsync();
namespace Hello
@@ -33,7 +33,8 @@ namespace Hello
ISayHello,
IHandleConsole,
IHandle,
- IHandle
+ IHandle,
+ IHandle
{
public async Task Handle(NewMessageReceived item)
{
@@ -50,13 +51,14 @@ namespace Hello
public async Task Handle(ConversationClosed item)
{
var goodbye = $"********************* {item.UserId} said {item.UserMessage} ************************";
- var evt = new Output
- {
- Message = goodbye
- };
- await PublishMessageAsync(evt).ConfigureAwait(false);
+ var evt = new Output { Message = goodbye };
+ await PublishMessageAsync(evt).ConfigureAwait(true);
+ await PublishMessageAsync(new Shutdown()).ConfigureAwait(false);
+ }
- // Signal shutdown.
+ public async Task Handle(Shutdown item)
+ {
+ Console.WriteLine("Shutting down...");
hostApplicationLifetime.StopApplication();
}
diff --git a/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj b/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj
index 797fe957b..e26b6c952 100644
--- a/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj
+++ b/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj
@@ -1,7 +1,7 @@
Exe
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/samples/Hello/HelloAgentState/Program.cs b/dotnet/samples/Hello/HelloAgentState/Program.cs
index 7c15c4c54..664689de8 100644
--- a/dotnet/samples/Hello/HelloAgentState/Program.cs
+++ b/dotnet/samples/Hello/HelloAgentState/Program.cs
@@ -9,7 +9,7 @@ using Microsoft.AutoGen.Agents;
var app = await AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
{
Message = "World"
-}, local: true);
+}, local: false);
await app.WaitForShutdownAsync();
diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj
index d8d7ebf8e..bf1bed178 100644
--- a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj
+++ b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj
index 8dfd6912e..d8034a01b 100644
--- a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj
+++ b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj b/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj
index a9227ea95..89d121b30 100644
--- a/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj
+++ b/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj
@@ -1,8 +1,10 @@
+
+
Exe
- net8.0
+ net8.0
enable
enable
true
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj
index 8296f7aa6..c48647198 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj
+++ b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj
@@ -5,7 +5,7 @@
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj b/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj
index bc739135d..18fcb9745 100644
--- a/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj
+++ b/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj
@@ -5,7 +5,7 @@
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/src/AutoGen.Core/Function/FunctionAttribute.cs b/dotnet/src/AutoGen.Core/Function/FunctionAttribute.cs
index 9418dc7fd..9367f5c6f 100644
--- a/dotnet/src/AutoGen.Core/Function/FunctionAttribute.cs
+++ b/dotnet/src/AutoGen.Core/Function/FunctionAttribute.cs
@@ -98,7 +98,7 @@ public class FunctionContract
[NamespaceKey] = contract.Namespace,
[ClassNameKey] = contract.ClassName,
},
- Parameters = [.. contract.Parameters?.Select(p => (AIFunctionParameterMetadata)p)],
+ Parameters = [.. contract.Parameters?.Select(p => (AIFunctionParameterMetadata)p)!],
};
}
}
diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentBase.cs b/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentBase.cs
index 14c2688c2..ee7b9e745 100644
--- a/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentBase.cs
+++ b/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentBase.cs
@@ -19,4 +19,5 @@ public interface IAgentBase
Task ReadAsync(AgentId agentId, CancellationToken cancellationToken = default) where T : IMessage, new();
ValueTask PublishEventAsync(CloudEvent item, CancellationToken cancellationToken = default);
ValueTask PublishEventAsync(string topic, IMessage evt, CancellationToken cancellationToken = default);
+ List Subscribe(string topic);
}
diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentRuntime.cs b/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentRuntime.cs
index 2125e57a8..aa5b5a13a 100644
--- a/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentRuntime.cs
+++ b/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentRuntime.cs
@@ -13,6 +13,7 @@ public interface IAgentRuntime
ValueTask ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
ValueTask SendResponseAsync(RpcRequest request, RpcResponse response, CancellationToken cancellationToken = default);
ValueTask SendRequestAsync(IAgentBase agent, RpcRequest request, CancellationToken cancellationToken = default);
+ ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default);
ValueTask PublishEventAsync(CloudEvent @event, CancellationToken cancellationToken = default);
void Update(Activity? activity, RpcRequest request);
void Update(Activity? activity, CloudEvent cloudEvent);
diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentWorker.cs
index 67a867d87..adce9be60 100644
--- a/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Abstractions/IAgentWorker.cs
@@ -8,6 +8,7 @@ public interface IAgentWorker
ValueTask PublishEventAsync(CloudEvent evt, CancellationToken cancellationToken = default);
ValueTask SendRequestAsync(IAgentBase agent, RpcRequest request, CancellationToken cancellationToken = default);
ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default);
+ ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default);
ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default);
ValueTask ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
}
diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj
index e24b52187..c680e2013 100644
--- a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj
+++ b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net8.0
enable
enable
AutoGen.Core
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/AgentBase.cs b/dotnet/src/Microsoft.AutoGen/Agents/AgentBase.cs
index 6fffdaadf..13b2e8519 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/AgentBase.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/AgentBase.cs
@@ -114,6 +114,27 @@ public abstract class AgentBase : IAgentBase, IHandle
break;
}
}
+ public List Subscribe(string topic)
+ {
+ Message message = new()
+ {
+ AddSubscriptionRequest = new()
+ {
+ RequestId = Guid.NewGuid().ToString(),
+ Subscription = new Subscription
+ {
+ TypeSubscription = new TypeSubscription
+ {
+ TopicType = topic,
+ AgentType = this.AgentId.Key
+ }
+ }
+ }
+ };
+ _context.SendMessageAsync(message).AsTask().Wait();
+
+ return new List { topic };
+ }
public async Task StoreAsync(AgentState state, CancellationToken cancellationToken = default)
{
await _context.StoreAsync(state, cancellationToken).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/AgentRuntime.cs b/dotnet/src/Microsoft.AutoGen/Agents/AgentRuntime.cs
index 86944cad3..fad372ce2 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/AgentRuntime.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/AgentRuntime.cs
@@ -45,6 +45,10 @@ internal sealed class AgentRuntime(AgentId agentId, IAgentWorker worker, ILogger
{
await worker.SendRequestAsync(agent, request, cancellationToken).ConfigureAwait(false);
}
+ public async ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default)
+ {
+ await worker.SendMessageAsync(message, cancellationToken).ConfigureAwait(false);
+ }
public async ValueTask PublishEventAsync(CloudEvent @event, CancellationToken cancellationToken = default)
{
await worker.PublishEventAsync(@event, cancellationToken).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj
index 3bc2b3acb..68b26f88b 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj
@@ -1,7 +1,7 @@
- net8.0
+ net8.0
enable
enable
Microsoft.AutoGen.Agents
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorker.cs
index 490051490..a69da96fb 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorker.cs
@@ -47,7 +47,7 @@ public class AgentWorker :
{
foreach (var (typeName, _) in _agentTypes)
{
- if (typeName == "Client") { continue; }
+ if (typeName == nameof(Client)) { continue; }
var agent = GetOrActivateAgent(new AgentId(typeName, cloudEvent.Source));
agent.ReceiveMessage(new Message { CloudEvent = cloudEvent });
}
@@ -63,6 +63,10 @@ public class AgentWorker :
{
return _mailbox.Writer.WriteAsync(new Message { Response = response }, cancellationToken);
}
+ public ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default)
+ {
+ return _mailbox.Writer.WriteAsync(message, cancellationToken);
+ }
public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default)
{
var agentId = value.AgentId ?? throw new InvalidOperationException("AgentId is required when saving AgentState.");
@@ -92,6 +96,10 @@ public class AgentWorker :
if (message == null) { continue; }
switch (message)
{
+ case Message.MessageOneofCase.AddSubscriptionResponse:
+ break;
+ case Message.MessageOneofCase.RegisterAgentTypeResponse:
+ break;
case Message msg:
var item = msg.CloudEvent;
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs
index 3736fc76c..fab29e86c 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs
@@ -29,7 +29,7 @@ public static class AgentWorkerHostingExtensions
public static IHostApplicationBuilder AddLocalAgentService(this IHostApplicationBuilder builder, bool useGrpc = true)
{
- return builder.AddAgentService(local: true, useGrpc);
+ return builder.AddAgentService(local: false, useGrpc);
}
public static WebApplication MapAgentService(this WebApplication app, bool local = false, bool useGrpc = true)
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorker.cs
index 431a5629c..48f075734 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorker.cs
@@ -85,6 +85,13 @@ public sealed class GrpcAgentWorker(
}
break;
+ case Message.MessageOneofCase.AddSubscriptionResponse:
+ if (!message.AddSubscriptionResponse.Success)
+ {
+ throw new InvalidOperationException($"Failed to add subscription: '{message.AddSubscriptionResponse.Error}'.");
+ }
+ break;
+
case Message.MessageOneofCase.CloudEvent:
// HACK: Send the message to an instance of each agent type
@@ -153,6 +160,13 @@ public sealed class GrpcAgentWorker(
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}.", channel.ToString());
+ break;
+ }
catch (Exception ex) when (!_shutdownCts.IsCancellationRequested)
{
item.WriteCompletionSource?.TrySetException(ex);
@@ -230,6 +244,11 @@ public sealed class GrpcAgentWorker(
await WriteChannelAsync(new Message { Request = request }, cancellationToken).ConfigureAwait(false);
}
// new is intentional
+ public new async ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default)
+ {
+ await WriteChannelAsync(message, cancellationToken).ConfigureAwait(false);
+ }
+ // new is intentional
public new async ValueTask PublishEventAsync(CloudEvent @event, CancellationToken cancellationToken = default)
{
await WriteChannelAsync(new Message { CloudEvent = @event }, cancellationToken).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index 670411b33..675742830 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -11,12 +11,12 @@ namespace Microsoft.AutoGen.Agents;
public static class GrpcAgentWorkerHostBuilderExtensions
{
- private const string _defaultAgentServiceAddress = "https://localhost:5001";
- public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBuilder builder, string agentServiceAddress = _defaultAgentServiceAddress)
+ 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);
+ options.Address = new Uri(agentServiceAddress ?? builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress);
options.ChannelOptionsActions.Add(channelOptions =>
{
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcGateway.cs
index 89e9c55c4..45477c8eb 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Grpc/GrpcGateway.cs
@@ -16,10 +16,13 @@ public sealed class GrpcGateway : BackgroundService, IGateway
private readonly IClusterClient _clusterClient;
private readonly ConcurrentDictionary _agentState = new();
private readonly IRegistryGrain _gatewayRegistry;
+ private readonly ISubscriptionsGrain _subscriptions;
private readonly IGateway _reference;
// The agents supported by each worker process.
private readonly ConcurrentDictionary> _supportedAgentTypes = [];
public readonly ConcurrentDictionary _workers = new();
+ private readonly ConcurrentDictionary _subscriptionsByAgentType = new();
+ private readonly ConcurrentDictionary> _subscriptionsByTopic = new();
// The mapping from agent id to worker process.
private readonly ConcurrentDictionary<(string Type, string Key), GrpcWorkerConnection> _agentDirectory = new();
@@ -33,6 +36,7 @@ public sealed class GrpcGateway : BackgroundService, IGateway
_clusterClient = clusterClient;
_reference = clusterClient.CreateObjectReference(this);
_gatewayRegistry = clusterClient.GetGrain(0);
+ _subscriptions = clusterClient.GetGrain(0);
}
public async ValueTask BroadcastEvent(CloudEvent evt)
{
@@ -102,16 +106,54 @@ public sealed class GrpcGateway : BackgroundService, IGateway
case Message.MessageOneofCase.RegisterAgentTypeRequest:
await RegisterAgentTypeAsync(connection, message.RegisterAgentTypeRequest);
break;
+ case Message.MessageOneofCase.AddSubscriptionRequest:
+ await AddSubscriptionAsync(connection, message.AddSubscriptionRequest);
+ break;
default:
- throw new InvalidOperationException($"Unknown message type for message '{message}'.");
+ // if it wasn't recognized return bad request
+ await RespondBadRequestAsync(connection, $"Unknown message type for message '{message}'.");
+ break;
};
}
+ private async ValueTask RespondBadRequestAsync(GrpcWorkerConnection connection, string error)
+ {
+ throw new RpcException(new Status(StatusCode.InvalidArgument, error));
+ }
+ private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, AddSubscriptionRequest request)
+ {
+ var topic = request.Subscription.TypeSubscription.TopicType;
+ var agentType = request.Subscription.TypeSubscription.AgentType;
+ _subscriptionsByAgentType[agentType] = request.Subscription;
+ _subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
+ await _subscriptions.Subscribe(topic, agentType);
+ //var response = new AddSubscriptionResponse { RequestId = request.RequestId, Error = "", Success = true };
+ Message response = new()
+ {
+ AddSubscriptionResponse = new()
+ {
+ RequestId = request.RequestId,
+ Error = "",
+ Success = true
+ }
+ };
+ await connection.ResponseStream.WriteAsync(response).ConfigureAwait(false);
+ }
private async ValueTask RegisterAgentTypeAsync(GrpcWorkerConnection connection, RegisterAgentTypeRequest msg)
{
connection.AddSupportedType(msg.Type);
_supportedAgentTypes.GetOrAdd(msg.Type, _ => []).Add(connection);
- await _gatewayRegistry.RegisterAgentType(msg.Type, _reference);
+ await _gatewayRegistry.RegisterAgentType(msg.Type, _reference).ConfigureAwait(true);
+ Message response = new()
+ {
+ RegisterAgentTypeResponse = new()
+ {
+ RequestId = msg.RequestId,
+ Error = "",
+ Success = true
+ }
+ };
+ await connection.ResponseStream.WriteAsync(response).ConfigureAwait(false);
}
private async ValueTask DispatchEventAsync(CloudEvent evt)
{
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Host.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Host.cs
index 5b725af0c..464536d54 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Host.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Host.cs
@@ -14,11 +14,11 @@ public static class Host
builder.AddServiceDefaults();
if (local)
{
- builder.AddLocalAgentService(useGrpc);
+ builder.AddLocalAgentService(useGrpc: useGrpc);
}
else
{
- builder.AddAgentService(useGrpc);
+ builder.AddAgentService(useGrpc: useGrpc);
}
var app = builder.Build();
app.MapAgentService(local, useGrpc);
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs
index f020f0bb6..f21096ccf 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs
@@ -15,7 +15,7 @@ namespace Microsoft.AutoGen.Agents;
public static class HostBuilderExtensions
{
- private const string _defaultAgentServiceAddress = "https://localhost:5001";
+ private const string _defaultAgentServiceAddress = "https://localhost:53071";
public static IHostApplicationBuilder AddAgent<
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TAgent>(this IHostApplicationBuilder builder, string typeName) where TAgent : AgentBase
@@ -28,12 +28,12 @@ public static class HostBuilderExtensions
public static IHostApplicationBuilder AddAgent(this IHostApplicationBuilder builder, string typeName, Type agentType)
{
builder.Services.AddKeyedSingleton("AgentTypes", (sp, key) => Tuple.Create(typeName, agentType));
-
return builder;
}
- public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilder builder, string agentServiceAddress = _defaultAgentServiceAddress, bool local = false)
+ public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilder builder, string? agentServiceAddress = null, bool local = false)
{
+ agentServiceAddress ??= builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress;
builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
// if !local, then add the gRPC client
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/ISubscriptionsGrain.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/ISubscriptionsGrain.cs
new file mode 100644
index 000000000..302df9ebf
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/ISubscriptionsGrain.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// ISubscriptionsGrain.cs
+
+namespace Microsoft.AutoGen.Agents;
+public interface ISubscriptionsGrain : IGrainWithIntegerKey
+{
+ ValueTask Subscribe(string agentType, string topic);
+ ValueTask Unsubscribe(string agentType, string topic);
+ ValueTask>> GetSubscriptions(string agentType);
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs
index c5114e3e7..cb7523126 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs
@@ -5,7 +5,7 @@ using Microsoft.AutoGen.Abstractions;
namespace Microsoft.AutoGen.Agents;
-public sealed class RegistryGrain : Grain, IRegistryGrain
+internal sealed class RegistryGrain : Grain, IRegistryGrain
{
// TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively.
private readonly Dictionary _workerStates = new();
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs
new file mode 100644
index 000000000..905dc8e91
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// SubscriptionsGrain.cs
+
+namespace Microsoft.AutoGen.Agents;
+
+internal sealed class SubscriptionsGrain([PersistentState("state", "PubSubStore")] IPersistentState state) : Grain, ISubscriptionsGrain
+{
+ private readonly Dictionary> _subscriptions = new();
+ public ValueTask>> GetSubscriptions(string agentType)
+ {
+ return new ValueTask>>(_subscriptions);
+ }
+ public ValueTask Subscribe(string agentType, string topic)
+ {
+ if (!_subscriptions.TryGetValue(topic, out var subscriptions))
+ {
+ subscriptions = _subscriptions[topic] = [];
+ }
+ if (!subscriptions.Contains(agentType))
+ {
+ subscriptions.Add(agentType);
+ }
+ _subscriptions[topic] = subscriptions;
+ state.State.Subscriptions = _subscriptions;
+ state.WriteStateAsync();
+
+ return ValueTask.CompletedTask;
+ }
+ public ValueTask Unsubscribe(string agentType, string topic)
+ {
+ if (!_subscriptions.TryGetValue(topic, out var subscriptions))
+ {
+ subscriptions = _subscriptions[topic] = [];
+ }
+ if (!subscriptions.Contains(agentType))
+ {
+ subscriptions.Remove(agentType);
+ }
+ _subscriptions[topic] = subscriptions;
+ state.State.Subscriptions = _subscriptions;
+ state.WriteStateAsync();
+ return ValueTask.CompletedTask;
+ }
+}
+public sealed class SubscriptionsState
+{
+ public Dictionary> Subscriptions { get; set; } = new();
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj
index 2358351de..970ae5db4 100644
--- a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj
+++ b/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj
@@ -1,6 +1,6 @@
- net8.0
+ net8.0
enable
enable
@@ -14,6 +14,6 @@
-
+
diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj
index fb47750fd..3c7fe5177 100644
--- a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj
+++ b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj
@@ -6,7 +6,7 @@
- net8.0
+ net8.0
enable
enable
diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj
index cf2446f93..b70161c7e 100644
--- a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj
+++ b/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj
@@ -1,6 +1,6 @@
- net8.0
+ net8.0
enable
enable
true
diff --git a/dotnet/test/AutoGen.AotCompatibility.Tests/AutoGen.AotCompatibility.Tests.csproj b/dotnet/test/AutoGen.AotCompatibility.Tests/AutoGen.AotCompatibility.Tests.csproj
index aec9660bb..379bca541 100644
--- a/dotnet/test/AutoGen.AotCompatibility.Tests/AutoGen.AotCompatibility.Tests.csproj
+++ b/dotnet/test/AutoGen.AotCompatibility.Tests/AutoGen.AotCompatibility.Tests.csproj
@@ -2,7 +2,7 @@
Exe
- net8.0
+ net8.0
enable
enable
true
diff --git a/dotnet/test/AutoGen.Tests/AutoGen.Tests.csproj b/dotnet/test/AutoGen.Tests/AutoGen.Tests.csproj
index 248a9e29b..367d74619 100644
--- a/dotnet/test/AutoGen.Tests/AutoGen.Tests.csproj
+++ b/dotnet/test/AutoGen.Tests/AutoGen.Tests.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/python/.gitignore b/python/.gitignore
index 186e847cc..677a888f2 100644
--- a/python/.gitignore
+++ b/python/.gitignore
@@ -172,3 +172,6 @@ docs/**/jupyter_execute
# Temporary files
tmp_code_*.py
+
+# .NET Development settings
+appsettings.Development.json
\ No newline at end of file