From 5f4d1dd35ea19fdb0aee56415716b9d75492b0cb Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 17 Dec 2024 13:49:15 -0800
Subject: [PATCH 001/110] wip

---
 dotnet/AutoGen.sln                            |  14 ++
 dotnet/Directory.Packages.props               |   3 +-
 .../Microsoft.AutoGen/Core/AgentsMetadata.cs  |  85 +++++++++
 .../TopicSubscriptionAttribute.cs             |   0
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs |   3 +-
 .../Services/Grpc/GrpcGatewayService.cs       |   2 +-
 .../GrpcGatewayServiceTests.cs                | 171 ++++++++++++++++++
 .../Helpers/Grpc/TestAsyncStreamReader.cs     |  69 +++++++
 .../Helpers/Grpc/TestGrpcClient.cs            |  36 ++++
 .../Helpers/Grpc/TestServerCallContext.cs     |  73 ++++++++
 .../Helpers/Grpc/TestServerStreamWriter.cs    |  86 +++++++++
 .../Helpers/Orleans/ClusterCollection.cs      |  10 +
 .../Helpers/Orleans/ClusterFixture.cs         |  21 +++
 .../Orleans/SiloBuilderConfigurator.cs        |  21 +++
 ...icrosoft.AutoGen.Runtime.Grpc.Tests.csproj |  25 +++
 .../TestAgent.cs                              |  46 +++++
 .../Microsoft.Autogen.Tests.Shared.csproj     |  26 +++
 .../Protos/messages.proto                     |  43 +++++
 18 files changed, 730 insertions(+), 4 deletions(-)
 create mode 100644 dotnet/src/Microsoft.AutoGen/Core/AgentsMetadata.cs
 rename dotnet/src/Microsoft.AutoGen/{Contracts => Core}/TopicSubscriptionAttribute.cs (100%)
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestAsyncStreamReader.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerCallContext.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerStreamWriter.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterCollection.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterFixture.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
 create mode 100644 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
 create mode 100644 dotnet/test/Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj
 create mode 100644 dotnet/test/Microsoft.Autogen.Tests.Shared/Protos/messages.proto

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index d0707a89a7fd..aaeb45125ac4 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -142,6 +142,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Agents",
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.AgentHost", "src\Microsoft.AutoGen\AgentHost\Microsoft.Autogen.AgentHost.csproj", "{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Runtime.Grpc.Tests", "test\Microsoft.AutoGen.Runtime.Grpc.Tests\Microsoft.AutoGen.Runtime.Grpc.Tests.csproj", "{0E7983BB-2602-421E-8B37-332E52870A10}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.Tests.Shared", "test\Microsoft.Autogen.Tests.Shared\Microsoft.Autogen.Tests.Shared.csproj", "{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -372,6 +376,14 @@ Global
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0E7983BB-2602-421E-8B37-332E52870A10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0E7983BB-2602-421E-8B37-332E52870A10}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0E7983BB-2602-421E-8B37-332E52870A10}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0E7983BB-2602-421E-8B37-332E52870A10}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -437,6 +449,8 @@ Global
 		{8457B68C-CC86-4A3F-8559-C1AE199EC366} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{3892C83E-7F5D-41DF-A88C-4854EAD38856} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
+		{0E7983BB-2602-421E-8B37-332E52870A10} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}
diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index 1e84c0badb2f..d0131825aab4 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -45,6 +45,7 @@
     <PackageVersion Include="MartinCostello.Logging.XUnit" Version="0.4.0" />
     <PackageVersion Include="Microsoft.AspNetCore.App" Version="8.0.4" />
     <PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
+    <PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.11" />
     <PackageVersion Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
     <PackageVersion Include="Microsoft.Bcl.AsyncInterfaces" Version="9.0.0" />
     <PackageVersion Include="Microsoft.Extensions.AI" Version="$(MicrosoftExtensionsAIVersion)" />
@@ -83,6 +84,7 @@
     <PackageVersion Include="Microsoft.Orleans.Server" Version="$(MicrosoftOrleans)" />
     <PackageVersion Include="Microsoft.Orleans.Streaming" Version="$(MicrosoftOrleans)" />
     <PackageVersion Include="Microsoft.Orleans.Streaming.EventHubs" Version="$(MicrosoftOrleans)" />
+    <PackageVersion Include="Microsoft.Orleans.TestingHost" Version="9.0.1" />
     <PackageVersion Include="Microsoft.SemanticKernel" Version="1.29.0" />
     <PackageVersion Include="Microsoft.SemanticKernel.Agents.Core" Version="$(MicrosoftSemanticKernelExperimentalVersion)" />
     <PackageVersion Include="Microsoft.SemanticKernel.Connectors.AzureOpenAI" Version="1.29.0" />
@@ -125,7 +127,6 @@
     <PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
     <PackageVersion Include="Moq" Version="4.20.72" />
     <PackageVersion Include="Microsoft.PowerShell.SDK" Version="7.4.5" />
-    <PackageVersion Include="Microsoft.AspNetCore.TestHost" Version="8.0.11" />
     <PackageVersion Include="coverlet.collector" Version="6.0.2" />
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentsMetadata.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentsMetadata.cs
new file mode 100644
index 000000000000..b3812d2e47cc
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentsMetadata.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentsMetadata.cs
+
+using System.Collections.Concurrent;
+using Google.Protobuf.Reflection;
+
+namespace Microsoft.AutoGen.Core;
+
+/// <summary>
+/// Represents a collection of event types and their associated metadata.
+/// </summary>
+public sealed class AgentsMetadata
+{
+    /// <summary>
+    /// Initializes a new instance of the <see cref="AgentsMetadata"/> class.
+    /// </summary>
+    /// <param name="typeRegistry">The type registry containing protobuf type information.</param>
+    /// <param name="types">A dictionary mapping event names to their corresponding types.</param>
+    /// <param name="eventsMap">A dictionary mapping types to a set of event names associated with those types.</param>
+    public AgentsMetadata(TypeRegistry typeRegistry, Dictionary<string, Type> types, Dictionary<Type, HashSet<string>> eventsMap, Dictionary<Type, HashSet<string>> topicsMap)
+    {
+        TypeRegistry = typeRegistry;
+        _types = new(types);
+        _eventsMap = new(eventsMap);
+        _topicsMap = new(topicsMap);
+    }
+
+    /// <summary>
+    /// Gets the type registry containing protobuf type information.
+    /// </summary>
+    public TypeRegistry TypeRegistry { get; }
+
+    private ConcurrentDictionary<string, Type> _types;
+
+    private ConcurrentDictionary<Type, HashSet<string>> _eventsMap;
+    private ConcurrentDictionary<Type, HashSet<string>> _topicsMap;
+
+    /// <summary>
+    /// Checks if a given type handles a specific event name.
+    /// </summary>
+    /// <param name="type">The type to check.</param>
+    /// <param name="eventName">The event name to check.</param>
+    /// <returns><c>true</c> if the type handles the event name; otherwise, <c>false</c>.</returns>
+    public bool CheckIfTypeHandles(Type type, string eventName)
+    {
+        if (_eventsMap.TryGetValue(type, out var events))
+        {
+            return events.Contains(eventName);
+        }
+        return false;
+    }
+
+    /// <summary>
+    /// Gets the event type by its name.
+    /// </summary>
+    /// <param name="type">The name of the event type.</param>
+    /// <returns>The event type if found; otherwise, <c>null</c>.</returns>
+    public Type? GetEventTypeByName(string type)
+    {
+        if (_types.TryGetValue(type, out var eventType))
+        {
+            return eventType;
+        }
+        return null;
+    }
+
+    public HashSet<string>? GetEventsForAgent(Type agent)
+    {
+        if (_eventsMap.TryGetValue(agent, out var events))
+        {
+            return events;
+        }
+        return null;
+    }
+
+    public HashSet<string>? GetTopicsForAgent(Type agent)
+    {
+        if (_topicsMap.TryGetValue(agent, out var topics))
+        {
+            return topics;
+        }
+        return null;
+    }
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Contracts/TopicSubscriptionAttribute.cs b/dotnet/src/Microsoft.AutoGen/Core/TopicSubscriptionAttribute.cs
similarity index 100%
rename from dotnet/src/Microsoft.AutoGen/Contracts/TopicSubscriptionAttribute.cs
rename to dotnet/src/Microsoft.AutoGen/Core/TopicSubscriptionAttribute.cs
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 2d63ab0870ca..30e316aa389b 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -28,8 +28,7 @@ public sealed class GrpcGateway : BackgroundService, IGateway
     private readonly ConcurrentDictionary<(string Type, string Key), GrpcWorkerConnection> _agentDirectory = new();
     // RPC
     private readonly ConcurrentDictionary<(GrpcWorkerConnection, string), TaskCompletionSource<RpcResponse>> _pendingRequests = new();
-    // InMemory Message Queue
-
+    public int WorkersCount => _workers.Count;
     public GrpcGateway(IClusterClient clusterClient, ILogger<GrpcGateway> logger)
     {
         _logger = logger;
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index ca4ffbb30c3e..a922f23c8e70 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -7,7 +7,7 @@
 namespace Microsoft.AutoGen.Runtime.Grpc;
 
 // gRPC service which handles communication between the agent worker and the cluster.
-internal sealed class GrpcGatewayService : AgentRpc.AgentRpcBase
+public sealed class GrpcGatewayService : AgentRpc.AgentRpcBase
 {
     private readonly GrpcGateway Gateway;
     public GrpcGatewayService(GrpcGateway gateway)
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
new file mode 100644
index 000000000000..507809fc3e5a
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -0,0 +1,171 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// GrpcGatewayServiceTests.cs
+
+using FluentAssertions;
+using Microsoft.AutoGen.Contracts;
+using Microsoft.AutoGen.Core;
+using Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Grpc;
+using Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Orleans;
+using Microsoft.Extensions.Logging;
+using Moq;
+using Tests.Events;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests;
+[Collection(ClusterCollection.Name)]
+public class GrpcGatewayServiceTests
+{
+    private readonly ClusterFixture _fixture;
+
+    public GrpcGatewayServiceTests(ClusterFixture fixture)
+    {
+        _fixture = fixture;
+    }
+    // Test broadcast Event
+    [Fact]
+    public async Task Test_OpenChannel()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        using var client = new TestGrpcClient();
+        
+        gateway.WorkersCount.Should().Be(0);
+        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
+        gateway.WorkersCount.Should().Be(1);
+    }
+
+    [Fact]
+    public async Task Test_Message_Exchange_Through_Gateway()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        using var client = new TestGrpcClient();
+
+        var assembly = typeof(PBAgent).Assembly;
+        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
+
+        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
+        var responseMessage = await client.ReadNext();
+
+        var connectionId = responseMessage!.OpenChannelResponse.ConnectionId;
+
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), connectionId), client.CallContext);
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), connectionId), client.CallContext);
+
+        var inputEvent = new NewMessageReceived { Message = $"Start-{connectionId}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
+
+        client.AddMessage(new Message { CloudEvent = inputEvent });
+        var newMessageReceived = await client.ReadNext();
+        newMessageReceived!.CloudEvent.Type.Should().Be(GetFullName(typeof(NewMessageReceived)));
+        newMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
+
+        // Simulate an agent, by publishing a new message in the request stream
+        var helloEvent = new Hello { Message = $"Hello test-{connectionId}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
+        client.AddMessage(new Message { CloudEvent = helloEvent });
+
+        var helloMessageReceived = await client.ReadNext();
+        helloMessageReceived!.CloudEvent.Type.Should().Be(GetFullName(typeof(Hello)));
+        helloMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
+    }
+
+    [Fact]
+    public async Task Test_Message_Goes_To_Right_Worker()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        using var client = new TestGrpcClient();
+
+        var assembly = typeof(PBAgent).Assembly;
+        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
+
+        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
+        var responseMessage = await client.ReadNext();
+
+        var connectionId = responseMessage!.OpenChannelResponse.ConnectionId;
+
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), connectionId), client.CallContext);
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), connectionId), client.CallContext);
+
+    }
+
+    [Fact]
+    public async Task Test_RegisterAgent_Should_Succeed()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        using var client = new TestGrpcClient();
+
+        var assembly = typeof(PBAgent).Assembly;
+        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
+
+        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
+        var responseMessage = await client.ReadNext();
+
+        var connectionId = responseMessage!.OpenChannelResponse.ConnectionId;
+
+        var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), connectionId), client.CallContext);
+        response.Success.Should().BeTrue();
+    }
+
+    [Fact]
+    public async Task Test_RegisterAgent_Should_Fail_For_Wrong_ConnectionId()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        using var client = new TestGrpcClient();
+
+        var assembly = typeof(PBAgent).Assembly;
+        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
+
+        var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), "faulty_connection_id"), client.CallContext);
+        response.Success.Should().BeFalse();
+    }
+
+    [Fact]
+    public async Task Test_SaveState()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        var callContext = TestServerCallContext.Create();
+
+        var response = await service.SaveState(new AgentState { AgentId = new AgentId { Key = "", Type = "" } }, callContext);
+
+        response.Should().NotBeNull();
+    }
+
+    [Fact]
+    public async Task Test_GetState()
+    {
+        var logger = Mock.Of<ILogger<GrpcGateway>>();
+        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
+        var service = new GrpcGatewayService(gateway);
+        var callContext = TestServerCallContext.Create();
+
+        var response = await service.GetState(new AgentId { Key = "", Type = "" }, callContext);
+
+        response.Should().NotBeNull();
+    }
+
+    private RegisterAgentTypeRequest CreateRegistrationRequest(AgentsMetadata eventTypes, Type type, string requestId)
+    {
+        var registration = new RegisterAgentTypeRequest
+        {
+            Type = type.Name,
+            RequestId = requestId
+        };
+        registration.Events.AddRange(eventTypes.GetEventsForAgent(type)?.ToList());
+        registration.Topics.AddRange(eventTypes.GetTopicsForAgent(type)?.ToList());
+
+        return registration;
+    }
+
+    private string GetFullName(Type type)
+    {
+        return ReflectionHelper.GetMessageDescriptor(type)!.FullName;
+    }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestAsyncStreamReader.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestAsyncStreamReader.cs
new file mode 100644
index 000000000000..4f26711d149f
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestAsyncStreamReader.cs
@@ -0,0 +1,69 @@
+#pragma warning disable IDE0073
+// Copyright 2019 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Threading.Channels;
+using Grpc.Core;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Grpc;
+
+public class TestAsyncStreamReader<T> : IDisposable, IAsyncStreamReader<T>
+                                           where T : class
+{
+    private readonly Channel<T> _channel;
+    private readonly ServerCallContext _serverCallContext;
+
+    public T Current { get; private set; } = null!;
+
+    public TestAsyncStreamReader(ServerCallContext serverCallContext)
+    {
+        _channel = Channel.CreateUnbounded<T>();
+        _serverCallContext = serverCallContext;
+    }
+
+    public void AddMessage(T message)
+    {
+        if (!_channel.Writer.TryWrite(message))
+        {
+            throw new InvalidOperationException("Unable to write message.");
+        }
+    }
+
+    public void Complete()
+    {
+        _channel.Writer.Complete();
+    }
+
+    public async Task<bool> MoveNext(CancellationToken cancellationToken)
+    {
+        _serverCallContext.CancellationToken.ThrowIfCancellationRequested();
+
+        if (await _channel.Reader.WaitToReadAsync(cancellationToken) &&
+            _channel.Reader.TryRead(out var message))
+        {
+            Current = message;
+            return true;
+        }
+        else
+        {
+            Current = null!;
+            return false;
+        }
+    }
+
+    public void Dispose()
+    {
+        Complete();
+    }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
new file mode 100644
index 000000000000..78724a43bf45
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// TestGrpcClient.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Grpc;
+internal sealed class TestGrpcClient: IDisposable
+{
+    public TestAsyncStreamReader<Message> RequestStream { get; }
+    public TestServerStreamWriter<Message> ResponseStream { get; }
+    public TestServerCallContext CallContext { get; }
+
+    public TestGrpcClient()
+    {
+        CallContext = TestServerCallContext.Create();
+        RequestStream = new TestAsyncStreamReader<Message>(CallContext);
+        ResponseStream = new TestServerStreamWriter<Message>(CallContext);
+    }
+
+    public async Task<Message> ReadNext()
+    {
+        var response = await ResponseStream.ReadNextAsync();
+        return response!;
+    }
+
+    public void AddMessage(Message message)
+    {
+        RequestStream.AddMessage(message);
+    }
+
+    public void Dispose()
+    {
+        RequestStream.Dispose();
+        ResponseStream.Dispose();
+    }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerCallContext.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerCallContext.cs
new file mode 100644
index 000000000000..47f25155602d
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerCallContext.cs
@@ -0,0 +1,73 @@
+#pragma warning disable IDE0073
+// Copyright 2019 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using Grpc.Core;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Grpc;
+
+public class TestServerCallContext : ServerCallContext
+{
+    private readonly Metadata _requestHeaders;
+    private readonly CancellationToken _cancellationToken;
+    private readonly Metadata _responseTrailers;
+    private readonly AuthContext _authContext;
+    private readonly Dictionary<object, object> _userState;
+    private WriteOptions? _writeOptions;
+
+    public Metadata? ResponseHeaders { get; private set; }
+
+    private TestServerCallContext(Metadata requestHeaders, CancellationToken cancellationToken)
+    {
+        _requestHeaders = requestHeaders;
+        _cancellationToken = cancellationToken;
+        _responseTrailers = new Metadata();
+        _authContext = new AuthContext(string.Empty, new Dictionary<string, List<AuthProperty>>());
+        _userState = new Dictionary<object, object>();
+    }
+
+    protected override string MethodCore => "MethodName";
+    protected override string HostCore => "HostName";
+    protected override string PeerCore => "PeerName";
+    protected override DateTime DeadlineCore { get; }
+    protected override Metadata RequestHeadersCore => _requestHeaders;
+    protected override CancellationToken CancellationTokenCore => _cancellationToken;
+    protected override Metadata ResponseTrailersCore => _responseTrailers;
+    protected override Status StatusCore { get; set; }
+    protected override WriteOptions? WriteOptionsCore { get => _writeOptions; set { _writeOptions = value; } }
+    protected override AuthContext AuthContextCore => _authContext;
+
+    protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions? options)
+    {
+        throw new NotImplementedException();
+    }
+
+    protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders)
+    {
+        if (ResponseHeaders != null)
+        {
+            throw new InvalidOperationException("Response headers have already been written.");
+        }
+
+        ResponseHeaders = responseHeaders;
+        return Task.CompletedTask;
+    }
+
+    protected override IDictionary<object, object> UserStateCore => _userState;
+
+    public static TestServerCallContext Create(Metadata? requestHeaders = null, CancellationToken cancellationToken = default)
+    {
+        return new TestServerCallContext(requestHeaders ?? new Metadata(), cancellationToken);
+    }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerStreamWriter.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerStreamWriter.cs
new file mode 100644
index 000000000000..ca2aeab2e410
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestServerStreamWriter.cs
@@ -0,0 +1,86 @@
+#pragma warning disable IDE0073
+// Copyright 2019 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+using System.Threading.Channels;
+using Grpc.Core;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Grpc;
+
+public class TestServerStreamWriter<T> : IDisposable, IServerStreamWriter<T> where T : class
+{
+    private readonly ServerCallContext _serverCallContext;
+    private readonly Channel<T> _channel;
+
+    public WriteOptions? WriteOptions { get; set; }
+
+    public TestServerStreamWriter(ServerCallContext serverCallContext)
+    {
+        _channel = Channel.CreateUnbounded<T>();
+
+        _serverCallContext = serverCallContext;
+    }
+
+    public void Complete()
+    {
+        _channel.Writer.Complete();
+    }
+
+    public IAsyncEnumerable<T> ReadAllAsync()
+    {
+        return _channel.Reader.ReadAllAsync();
+    }
+
+    public async Task<T?> ReadNextAsync()
+    {
+        if (await _channel.Reader.WaitToReadAsync())
+        {
+            _channel.Reader.TryRead(out var message);
+            return message;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    public Task WriteAsync(T message, CancellationToken cancellationToken)
+    {
+        if (cancellationToken.IsCancellationRequested)
+        {
+            return Task.FromCanceled(cancellationToken);
+        }
+        if (_serverCallContext.CancellationToken.IsCancellationRequested)
+        {
+            return Task.FromCanceled(_serverCallContext.CancellationToken);
+        }
+
+        if (!_channel.Writer.TryWrite(message))
+        {
+            throw new InvalidOperationException("Unable to write message.");
+        }
+
+        return Task.CompletedTask;
+    }
+
+    public Task WriteAsync(T message)
+    {
+        return WriteAsync(message, CancellationToken.None);
+    }
+
+    public void Dispose()
+    {
+        Complete();
+    }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterCollection.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterCollection.cs
new file mode 100644
index 000000000000..d61dc7b21c50
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterCollection.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// ClusterCollection.cs
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Orleans;
+
+[CollectionDefinition(Name)]
+public sealed class ClusterCollection : ICollectionFixture<ClusterFixture>
+{
+    public const string Name = nameof(ClusterCollection);
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterFixture.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterFixture.cs
new file mode 100644
index 000000000000..9db2f7f654d4
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/ClusterFixture.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// ClusterFixture.cs
+
+using Orleans.TestingHost;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Orleans;
+
+public sealed class ClusterFixture : IDisposable
+{
+    public ClusterFixture()
+    {
+        var builder = new TestClusterBuilder();
+        builder.AddSiloBuilderConfigurator<SiloBuilderConfigurator>();
+        Cluster = builder.Build();
+        Cluster.Deploy();
+
+    }
+    public TestCluster Cluster { get; }
+
+    void IDisposable.Dispose() => Cluster.StopAllSilos();
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs
new file mode 100644
index 000000000000..fb345777a82b
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// SiloBuilderConfigurator.cs
+
+using Orleans.Serialization;
+using Orleans.TestingHost;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Orleans;
+
+public class SiloBuilderConfigurator : ISiloConfigurator
+{
+    public void Configure(ISiloBuilder siloBuilder)
+    {
+        siloBuilder.ConfigureServices(services =>
+        {
+            services.AddSerializer(a => a.AddProtobufSerializer());
+        });
+        siloBuilder.AddMemoryStreams("StreamProvider")
+                    .AddMemoryGrainStorage("PubSubStore")
+                    .AddMemoryGrainStorage("AgentStateStore");
+    }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
new file mode 100644
index 000000000000..1cdeb3f295e8
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
@@ -0,0 +1,25 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <IsTestProject>True</IsTestProject>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Microsoft.AspNetCore.TestHost" />
+    <PackageReference Include="Microsoft.Orleans.TestingHost" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AutoGen\Runtime.Grpc\Microsoft.AutoGen.Runtime.Grpc.csproj" />
+    <ProjectReference Include="..\Microsoft.Autogen.Tests.Shared\Microsoft.Autogen.Tests.Shared.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Using Include="Xunit" />
+  </ItemGroup>
+
+</Project>
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
new file mode 100644
index 000000000000..fc8260f51d8b
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// TestAgent.cs
+
+using System.Collections.Concurrent;
+using Microsoft.AutoGen.Core;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Logging;
+using Tests.Events;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Tests;
+
+[TopicSubscription("gh-gh-gh")]
+public class PBAgent([FromKeyedServices("EventTypes")] AgentsMetadata eventTypes, ILogger<Agent>? logger = null)
+    : Agent(eventTypes, logger)
+    , IHandle<NewMessageReceived>
+    , IHandle<GoodBye>
+{
+    public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
+    {
+        ReceivedMessages[AgentId.Key] = item.Message;
+        var hello = new Hello { Message = item.Message };
+        await PublishEventAsync(hello);
+    }
+    public Task Handle(GoodBye item, CancellationToken cancellationToken)
+    {
+        _logger.LogInformation($"Received GoodBye message {item.Message}");
+        return Task.CompletedTask;
+    }
+
+    public static ConcurrentDictionary<string, object> ReceivedMessages { get; private set; } = new();
+}
+
+[TopicSubscription("gh-gh-gh")]
+public class GMAgent([FromKeyedServices("EventTypes")] AgentsMetadata eventTypes, ILogger<Agent>? logger = null)
+    : Agent(eventTypes, logger)
+    , IHandle<Hello>
+{
+    public async Task Handle(Hello item, CancellationToken cancellationToken)
+    {
+        _logger.LogInformation($"Received Hello message {item.Message}");
+        ReceivedMessages[AgentId.Key] = item.Message;
+        await PublishEventAsync(new GoodBye { Message = "" });
+    }
+
+    public static ConcurrentDictionary<string, object> ReceivedMessages { get; private set; } = new();
+}
diff --git a/dotnet/test/Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj b/dotnet/test/Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj
new file mode 100644
index 000000000000..45b3dcc45309
--- /dev/null
+++ b/dotnet/test/Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj
@@ -0,0 +1,26 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+
+    <IsPackable>false</IsPackable>
+    <IsTestProject>true</IsTestProject>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Protobuf Include=".\Protos\messages.proto" GrpcServices="Client;Server" Link="Protos\messages.proto" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="Grpc.AspNetCore" />
+    <PackageReference Include="Grpc.Net.ClientFactory" />
+    <PackageReference Include="Grpc.Tools" PrivateAssets="All" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Using Include="Xunit" />
+  </ItemGroup>
+
+</Project>
diff --git a/dotnet/test/Microsoft.Autogen.Tests.Shared/Protos/messages.proto b/dotnet/test/Microsoft.Autogen.Tests.Shared/Protos/messages.proto
new file mode 100644
index 000000000000..cb68d45e7550
--- /dev/null
+++ b/dotnet/test/Microsoft.Autogen.Tests.Shared/Protos/messages.proto
@@ -0,0 +1,43 @@
+syntax = "proto3";
+
+package tests;
+
+option csharp_namespace = "Tests.Events";
+message TextMessage {
+    string message = 1;
+    string source = 2;
+}
+message Hello {
+      string message = 1;
+}
+message InputProcessed {
+      string route = 1;
+}
+message Output {
+      string message = 1;
+}
+message OutputWritten {
+      string route = 1;
+}
+message IOError {
+      string message = 1;
+}
+message NewMessageReceived {
+      string message = 1;
+}
+message ResponseGenerated {
+      string response = 1;
+}
+message GoodBye {
+      string message = 1;
+}
+message MessageStored {
+      string message = 1;
+}
+message ConversationClosed {
+  string user_id = 1;
+  string user_message = 2;
+}
+message Shutdown {
+      string message = 1;
+}

From 56e47cffa88c6a25f69548cf6f184ebe556f0c91 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 17 Dec 2024 14:48:45 -0800
Subject: [PATCH 002/110] wip working on grpcgateway

---
 .../Runtime.Grpc/Abstractions/IAgentGrain.cs  |  10 +
 .../Runtime.Grpc/Abstractions/IGateway.cs     |  16 ++
 .../Runtime.Grpc/Abstractions/IRegistry.cs    |  85 +++++++
 .../Abstractions/IRegistryGrain.cs            |  10 +
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 111 +++++----
 .../Runtime.Grpc/Services/IGateway.cs         |  14 --
 .../Services/Orleans/AgentsRegistry.cs        | 225 ++++++++++++++++++
 .../Services/Orleans/AgentsRegistryState.cs   |  12 +
 .../Services/Orleans/IRegistryGrain.cs        |  15 --
 .../AddSubscriptionRequestSurrogate.cs        |  39 +++
 .../AddSubscriptionResponseSurrogate.cs       |  41 ++++
 .../Orleans/Surrogates/AgentIdSurrogate.cs    |  38 +++
 .../Orleans/Surrogates/AgentStateSurrogate.cs |  56 +++++
 .../Orleans/Surrogates/CloudEventSurrogate.cs |  46 ++++
 .../RegisterAgentTypeRequestSurrogate.cs      |  48 ++++
 .../RegisterAgentTypeResponseSurrogate.cs     |  41 ++++
 .../Orleans/Surrogates/RpcRequestSurrogate.cs |  54 +++++
 .../Surrogates/RpcResponseSurrogate.cs        |  46 ++++
 .../Surrogates/TypePrefixSubscription.cs      |  36 +++
 .../Orleans/Surrogates/TypeSubscription.cs    |  36 +++
 20 files changed, 905 insertions(+), 74 deletions(-)
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IAgentGrain.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs
 delete mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/IGateway.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
 delete mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/IRegistryGrain.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentIdSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/CloudEventSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeResponseSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcRequestSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcResponseSurrogate.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IAgentGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IAgentGrain.cs
new file mode 100644
index 000000000000..947b6b0cbc0a
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IAgentGrain.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// IAgentGrain.cs
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
+
+internal interface IAgentGrain : IGrainWithStringKey
+{
+    ValueTask<Contracts.AgentState> ReadStateAsync();
+    ValueTask<string> WriteStateAsync(Contracts.AgentState state, string eTag);
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
new file mode 100644
index 000000000000..dd7263729378
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// IGateway.cs
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
+
+public interface IGateway : IGrainObserver
+{
+    ValueTask<RpcResponse> InvokeRequest(RpcRequest request);
+    ValueTask BroadcastEvent(CloudEvent evt);
+    ValueTask StoreAsync(Contracts.AgentState value);
+    ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId);
+    ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request);
+    ValueTask<AddSubscriptionResponse> AddSubscriptionAsync(AddSubscriptionRequest request);
+    Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent);
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
new file mode 100644
index 000000000000..ffb053956ffc
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// IRegistry.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
+
+/// <summary>
+/// Interface for managing agent registration, placement, and subscriptions.
+/// </summary>
+public interface IRegistry
+{
+    /// <summary>
+    /// Gets or places an agent based on the provided agent ID.
+    /// </summary>
+    /// <param name="agentId">The ID of the agent.</param>
+    /// <returns>A tuple containing the worker and a boolean indicating if it's a new placement.</returns>
+    ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId);
+
+    /// <summary>
+    /// Removes a worker from the registry.
+    /// </summary>
+    /// <param name="worker">The worker to remove.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    ValueTask RemoveWorker(IGateway worker);
+
+    /// <summary>
+    /// Registers a new agent type with the specified worker.
+    /// </summary>
+    /// <param name="request">The request containing agent type details.</param>
+    /// <param name="worker">The worker to register the agent type with.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    ValueTask RegisterAgentType(RegisterAgentTypeRequest request, IGateway worker);
+
+    /// <summary>
+    /// Adds a new worker to the registry.
+    /// </summary>
+    /// <param name="worker">The worker to add.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    ValueTask AddWorker(IGateway worker);
+
+    /// <summary>
+    /// Unregisters an agent type from the specified worker.
+    /// </summary>
+    /// <param name="type">The type of the agent to unregister.</param>
+    /// <param name="worker">The worker to unregister the agent type from.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    ValueTask UnregisterAgentType(string type, IGateway worker);
+
+    /// <summary>
+    /// Gets a compatible worker for the specified agent type.
+    /// </summary>
+    /// <param name="type">The type of the agent.</param>
+    /// <returns>A task representing the asynchronous operation, with the compatible worker as the result.</returns>
+    ValueTask<IGateway?> GetCompatibleWorker(string type);
+
+    /// <summary>
+    /// Gets a list of agents subscribed to and handling the specified topic and event type.
+    /// </summary>
+    /// <param name="topic">The topic to check subscriptions for.</param>
+    /// <param name="eventType">The event type to check subscriptions for.</param>
+    /// <returns>A task representing the asynchronous operation, with the list of agent IDs as the result.</returns>
+    ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType);
+
+    /// <summary>
+    /// Subscribes an agent to a topic.
+    /// </summary>
+    /// <param name="request">The subscription request.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    ValueTask SubscribeAsync(AddSubscriptionRequest request);
+
+    /// <summary>
+    /// Unsubscribes an agent from a topic.
+    /// </summary>
+    /// <param name="request">The unsubscription request.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    ValueTask UnsubscribeAsync(AddSubscriptionRequest request); // TODO: This should have its own request type.
+
+    /// <summary>
+    /// Gets the subscriptions for a specified agent type.
+    /// </summary>
+    /// <param name="agentType">The type of the agent.</param>
+    /// <returns>A task representing the asynchronous operation, with the subscriptions as the result.</returns>
+    ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType);
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs
new file mode 100644
index 000000000000..2f48b051b38b
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// IRegistryGrain.cs
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
+
+/// <summary>
+/// Orleans specific interface, needed to mark the key
+/// </summary>
+public interface IRegistryGrain : IRegistry, IGrainWithIntegerKey
+{ }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 30e316aa389b..146e7a8e257d 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -4,6 +4,7 @@
 using System.Collections.Concurrent;
 using Grpc.Core;
 using Microsoft.AutoGen.Contracts;
+using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 
@@ -14,13 +15,13 @@ public sealed class GrpcGateway : BackgroundService, IGateway
     private static readonly TimeSpan s_agentResponseTimeout = TimeSpan.FromSeconds(30);
     private readonly ILogger<GrpcGateway> _logger;
     private readonly IClusterClient _clusterClient;
-    private readonly ConcurrentDictionary<string, AgentState> _agentState = new();
+    //private readonly ConcurrentDictionary<string, AgentState> _agentState = new();
     private readonly IRegistryGrain _gatewayRegistry;
-    private readonly ISubscriptionsGrain _subscriptions;
     private readonly IGateway _reference;
     // The agents supported by each worker process.
     private readonly ConcurrentDictionary<string, List<GrpcWorkerConnection>> _supportedAgentTypes = [];
     public readonly ConcurrentDictionary<IConnection, IConnection> _workers = new();
+    internal readonly ConcurrentDictionary<string, GrpcWorkerConnection> _workersByConnection = new();
     private readonly ConcurrentDictionary<string, Subscription> _subscriptionsByAgentType = new();
     private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
 
@@ -35,7 +36,69 @@ public GrpcGateway(IClusterClient clusterClient, ILogger<GrpcGateway> logger)
         _clusterClient = clusterClient;
         _reference = clusterClient.CreateObjectReference<IGateway>(this);
         _gatewayRegistry = clusterClient.GetGrain<IRegistryGrain>(0);
-        _subscriptions = clusterClient.GetGrain<ISubscriptionsGrain>(0);
+    }
+    public async ValueTask<RpcResponse> InvokeRequest(RpcRequest request, CancellationToken cancellationToken = default)
+    {
+        var agentId = (request.Target.Type, request.Target.Key);
+        if (!_agentDirectory.TryGetValue(agentId, out var connection) || connection.Completion.IsCompleted == true)
+        {
+            // Activate the agent on a compatible worker process.
+            if (_supportedAgentTypes.TryGetValue(request.Target.Type, out var workers))
+            {
+                connection = workers[Random.Shared.Next(workers.Count)];
+                _agentDirectory[agentId] = connection;
+            }
+            else
+            {
+                return new(new RpcResponse { Error = "Agent not found." });
+            }
+        }
+        // Proxy the request to the agent.
+        var originalRequestId = request.RequestId;
+        var newRequestId = Guid.NewGuid().ToString();
+        var completion = _pendingRequests[(connection, newRequestId)] = new(TaskCreationOptions.RunContinuationsAsynchronously);
+        request.RequestId = newRequestId;
+        await connection.ResponseStream.WriteAsync(new Message { Request = request }, cancellationToken).ConfigureAwait(false);
+        // Wait for the response and send it back to the caller.
+        var response = await completion.Task.WaitAsync(s_agentResponseTimeout);
+        response.RequestId = originalRequestId;
+        return response;
+    }
+    public async ValueTask StoreAsync(AgentState value)
+    {
+        _ = value.AgentId ?? throw new ArgumentNullException(nameof(value.AgentId));
+        var agentState = _clusterClient.GetGrain<IAgentGrain>($"{value.AgentId.Type}:{value.AgentId.Key}");
+        await agentState.WriteStateAsync(value, value.ETag);
+    }
+    public async ValueTask<AgentState> ReadAsync(AgentId agentId)
+    {
+        var agentState = _clusterClient.GetGrain<IAgentGrain>($"{agentId.Type}:{agentId.Key}");
+        return await agentState.ReadStateAsync();
+    }
+    public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request)
+    {
+        try
+        {
+            var connection = _workersByConnection[request.RequestId];
+            connection.AddSupportedType(request.Type);
+            _supportedAgentTypes.GetOrAdd(request.Type, _ => []).Add(connection);
+
+            await _gatewayRegistry.RegisterAgentType(request, _reference).ConfigureAwait(true);
+            return new RegisterAgentTypeResponse
+            {
+                Success = true,
+                RequestId = request.RequestId
+            };
+        }
+        catch (Exception ex)
+        {
+            return new RegisterAgentTypeResponse
+            {
+                Success = false,
+                RequestId = request.RequestId,
+                Error = ex.Message
+            };
+        }
     }
     public async ValueTask BroadcastEvent(CloudEvent evt)
     {
@@ -253,20 +316,6 @@ internal Task ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream,
         _workers[workerProcess] = workerProcess;
         return workerProcess.Completion;
     }
-    public async ValueTask StoreAsync(AgentState value)
-    {
-        var agentId = value.AgentId ?? throw new ArgumentNullException(nameof(value.AgentId));
-        _agentState[agentId.Key] = value;
-    }
-
-    public async ValueTask<AgentState> ReadAsync(AgentId agentId)
-    {
-        if (_agentState.TryGetValue(agentId.Key, out var state))
-        {
-            return state;
-        }
-        return new AgentState { AgentId = agentId };
-    }
     internal void OnRemoveWorkerProcess(GrpcWorkerConnection workerProcess)
     {
         _workers.TryRemove(workerProcess, out _);
@@ -287,34 +336,6 @@ internal void OnRemoveWorkerProcess(GrpcWorkerConnection workerProcess)
             }
         }
     }
-    public async ValueTask<RpcResponse> InvokeRequest(RpcRequest request, CancellationToken cancellationToken = default)
-    {
-        (string Type, string Key) agentId = (request.Target.Type, request.Target.Key);
-        if (!_agentDirectory.TryGetValue(agentId, out var connection) || connection.Completion.IsCompleted)
-        {
-            // Activate the agent on a compatible worker process.
-            if (_supportedAgentTypes.TryGetValue(request.Target.Type, out var workers))
-            {
-                connection = workers[Random.Shared.Next(workers.Count)];
-                _agentDirectory[agentId] = connection;
-            }
-            else
-            {
-                return new(new RpcResponse { Error = "Agent not found." });
-            }
-        }
-        // Proxy the request to the agent.
-        var originalRequestId = request.RequestId;
-        var newRequestId = Guid.NewGuid().ToString();
-        var completion = _pendingRequests[(connection, newRequestId)] = new(TaskCreationOptions.RunContinuationsAsynchronously);
-        request.RequestId = newRequestId;
-        await connection.ResponseStream.WriteAsync(new Message { Request = request }, cancellationToken).ConfigureAwait(false);
-        // Wait for the response and send it back to the caller.
-        var response = await completion.Task.WaitAsync(s_agentResponseTimeout);
-        response.RequestId = originalRequestId;
-        return response;
-    }
-
     async ValueTask<RpcResponse> IGateway.InvokeRequest(RpcRequest request)
     {
         return await this.InvokeRequest(request).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/IGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/IGateway.cs
deleted file mode 100644
index 463ae4e532af..000000000000
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/IGateway.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// IGateway.cs
-using Microsoft.AutoGen.Contracts;
-
-namespace Microsoft.AutoGen.Runtime.Grpc;
-
-public interface IGateway : IGrainObserver
-{
-    ValueTask<RpcResponse> InvokeRequest(RpcRequest request);
-    ValueTask BroadcastEvent(CloudEvent evt);
-    ValueTask StoreAsync(AgentState value);
-    ValueTask<AgentState> ReadAsync(AgentId agentId);
-    Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent);
-}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
new file mode 100644
index 000000000000..30cd40ad35a4
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
@@ -0,0 +1,225 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentsRegistry.cs
+
+using Microsoft.AutoGen.Contracts;
+using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
+
+namespace Microsoft.AutoGen.Runtime.Grpc;
+internal sealed class AgentsRegistry([PersistentState("state", "AgentStateStore")] IPersistentState<AgentsRegistryState> state) : Grain, IGrainRegistry
+{
+    // TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively.
+    private readonly Dictionary<IGateway, WorkerState> _workerStates = new();
+    private readonly Dictionary<string, List<IGateway>> _supportedAgentTypes = [];
+    private readonly Dictionary<(string Type, string Key), IGateway> _agentDirectory = [];
+    private readonly TimeSpan _agentTimeout = TimeSpan.FromMinutes(1);
+
+    public override Task OnActivateAsync(CancellationToken cancellationToken)
+    {
+        this.RegisterGrainTimer(static state => state.PurgeInactiveWorkers(), this, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
+        return base.OnActivateAsync(cancellationToken);
+    }
+
+    public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType)
+    {
+        // get all agent types that are subscribed to the topic
+        var subscribedAgents = state.State.TopicToAgentTypesMap[topic];
+        // get all agent types that are handling the event
+        var handlingAgents = state.State.EventsToAgentTypesMap[eventType];
+        // return the intersection of the two sets
+        return new(subscribedAgents.Intersect(handlingAgents).ToList());
+    }
+    public ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId)
+    {
+        // TODO: Clarify the logic
+        bool isNewPlacement;
+        if (!_agentDirectory.TryGetValue((agentId.Type, agentId.Key), out var worker) || !_workerStates.ContainsKey(worker))
+        {
+            worker = GetCompatibleWorkerCore(agentId.Type);
+            if (worker is not null)
+            {
+                // New activation.
+                _agentDirectory[(agentId.Type, agentId.Key)] = worker;
+                isNewPlacement = true;
+            }
+            else
+            {
+                // No activation, and failed to place.
+                isNewPlacement = false;
+            }
+        }
+        else
+        {
+            // Existing activation.
+            isNewPlacement = false;
+        }
+        return new((worker, isNewPlacement));
+    }
+    public ValueTask RemoveWorker(IGateway worker)
+    {
+        if (_workerStates.Remove(worker, out var state))
+        {
+            foreach (var type in state.SupportedTypes)
+            {
+                if (_supportedAgentTypes.TryGetValue(type, out var workers))
+                {
+                    workers.Remove(worker);
+                }
+            }
+        }
+        return ValueTask.CompletedTask;
+    }
+    public async ValueTask RegisterAgentType(RegisterAgentTypeRequest registration, IGateway worker)
+    {
+        if (!_supportedAgentTypes.TryGetValue(registration.Type, out var supportedAgentTypes))
+        {
+            supportedAgentTypes = _supportedAgentTypes[registration.Type] = [];
+        }
+
+        if (!supportedAgentTypes.Contains(worker))
+        {
+            supportedAgentTypes.Add(worker);
+        }
+
+        var workerState = GetOrAddWorker(worker);
+        workerState.SupportedTypes.Add(registration.Type);
+        state.State.AgentsToEventsMap[registration.Type] = new HashSet<string>(registration.Events);
+        state.State.AgentsToTopicsMap[registration.Type] = new HashSet<string>(registration.Topics);
+
+        // construct the inverse map for topics and agent types
+        foreach (var topic in registration.Topics)
+        {
+            if (!state.State.TopicToAgentTypesMap.TryGetValue(topic, out var topicSet))
+            {
+                topicSet = new HashSet<string>();
+                state.State.TopicToAgentTypesMap[topic] = topicSet;
+            }
+
+            topicSet.Add(registration.Type);
+        }
+
+        // construct the inverse map for events and agent types
+        foreach (var evt in registration.Events)
+        {
+            if (!state.State.EventsToAgentTypesMap.TryGetValue(evt, out var eventSet))
+            {
+                eventSet = new HashSet<string>();
+                state.State.EventsToAgentTypesMap[evt] = eventSet;
+            }
+
+            eventSet.Add(registration.Type);
+        }
+        await state.WriteStateAsync().ConfigureAwait(false);
+    }
+    public ValueTask AddWorker(IGateway worker)
+    {
+        GetOrAddWorker(worker);
+        return ValueTask.CompletedTask;
+    }
+    public ValueTask UnregisterAgentType(string type, IGateway worker)
+    {
+        if (_workerStates.TryGetValue(worker, out var state))
+        {
+            state.SupportedTypes.Remove(type);
+        }
+
+        if (_supportedAgentTypes.TryGetValue(type, out var workers))
+        {
+            workers.Remove(worker);
+        }
+        return ValueTask.CompletedTask;
+    }
+    private Task PurgeInactiveWorkers()
+    {
+        foreach (var (worker, state) in _workerStates)
+        {
+            if (DateTimeOffset.UtcNow - state.LastSeen > _agentTimeout)
+            {
+                _workerStates.Remove(worker);
+                foreach (var type in state.SupportedTypes)
+                {
+                    if (_supportedAgentTypes.TryGetValue(type, out var workers))
+                    {
+                        workers.Remove(worker);
+                    }
+                }
+            }
+        }
+
+        return Task.CompletedTask;
+    }
+
+    private WorkerState GetOrAddWorker(IGateway worker)
+    {
+        if (!_workerStates.TryGetValue(worker, out var workerState))
+        {
+            workerState = _workerStates[worker] = new();
+        }
+
+        workerState.LastSeen = DateTimeOffset.UtcNow;
+        return workerState;
+    }
+
+    public ValueTask<IGateway?> GetCompatibleWorker(string type) => new(GetCompatibleWorkerCore(type));
+
+    private IGateway? GetCompatibleWorkerCore(string type)
+    {
+        if (_supportedAgentTypes.TryGetValue(type, out var workers))
+        {
+            // Return a random compatible worker.
+            return workers[Random.Shared.Next(workers.Count)];
+        }
+
+        return null;
+    }
+
+    public async ValueTask SubscribeAsync(AddSubscriptionRequest sub)
+    {
+        switch (sub.Subscription.SubscriptionCase)
+        {
+            case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
+                break;
+            case Subscription.SubscriptionOneofCase.TypeSubscription:
+                {
+                    // add the topic to the set of topics for the agent type
+                    state.State.AgentsToTopicsMap.TryGetValue(sub.Subscription.TypeSubscription.AgentType, out var topics);
+                    if (topics is null)
+                    {
+                        topics = new HashSet<string>();
+                        state.State.AgentsToTopicsMap[sub.Subscription.TypeSubscription.AgentType] = topics;
+                    }
+                    topics.Add(sub.Subscription.TypeSubscription.TopicType);
+
+                    // add the agent type to the set of agent types for the topic
+                    state.State.TopicToAgentTypesMap.TryGetValue(sub.Subscription.TypeSubscription.TopicType, out var agents);
+                    if (agents is null)
+                    {
+                        agents = new HashSet<string>();
+                        state.State.TopicToAgentTypesMap[sub.Subscription.TypeSubscription.TopicType] = agents;
+                    }
+
+                    agents.Add(sub.Subscription.TypeSubscription.AgentType);
+
+                    break;
+                }
+            default:
+                throw new InvalidOperationException("Invalid subscription type");
+        }
+        await state.WriteStateAsync().ConfigureAwait(false);
+    }
+    public async ValueTask UnsubscribeAsync(AddSubscriptionRequest request)
+    {
+        throw new NotImplementedException();
+    }
+
+    public ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType)
+    {
+        throw new NotImplementedException();
+    }
+
+    private sealed class WorkerState
+    {
+        public HashSet<string> SupportedTypes { get; set; } = [];
+        public DateTimeOffset LastSeen { get; set; }
+    }
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
new file mode 100644
index 000000000000..122821270f65
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
@@ -0,0 +1,12 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentsRegistryState.cs
+
+namespace Microsoft.AutoGen.Runtime.Grpc;
+
+public class AgentsRegistryState
+{
+    public Dictionary<string, HashSet<string>> AgentsToEventsMap { get; set; } = [];
+    public Dictionary<string, HashSet<string>> AgentsToTopicsMap { get; set; } = [];
+    public Dictionary<string, HashSet<string>> TopicToAgentTypesMap { get; set; } = [];
+    public Dictionary<string, HashSet<string>> EventsToAgentTypesMap { get; set; } = [];
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/IRegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/IRegistryGrain.cs
deleted file mode 100644
index 1c817add3074..000000000000
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/IRegistryGrain.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// IRegistryGrain.cs
-using Microsoft.AutoGen.Contracts;
-
-namespace Microsoft.AutoGen.Runtime.Grpc;
-
-public interface IRegistryGrain : IGrainWithIntegerKey
-{
-    ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId);
-    ValueTask RemoveWorker(IGateway worker);
-    ValueTask RegisterAgentType(string type, IGateway worker);
-    ValueTask AddWorker(IGateway worker);
-    ValueTask UnregisterAgentType(string type, IGateway worker);
-    ValueTask<IGateway?> GetCompatibleWorker(string type);
-}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
new file mode 100644
index 000000000000..e732c3ffc982
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AddSubscriptionRequestSurrogate.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct AddSubscriptionRequestSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public Subscription Subscription;
+}
+
+[RegisterConverter]
+public sealed class AddSubscriptionRequestSurrogateConverter :
+    IConverter<AddSubscriptionRequest, AddSubscriptionRequestSurrogate>
+{
+    public AddSubscriptionRequest ConvertFromSurrogate(
+        in AddSubscriptionRequestSurrogate surrogate)
+    {
+        var request = new AddSubscriptionRequest()
+        {
+            RequestId = surrogate.RequestId,
+            Subscription = surrogate.Subscription
+        };
+        return request;
+    }
+
+    public AddSubscriptionRequestSurrogate ConvertToSurrogate(
+        in AddSubscriptionRequest value) =>
+        new AddSubscriptionRequestSurrogate
+        {
+            RequestId = value.RequestId,
+            Subscription = value.Subscription
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
new file mode 100644
index 000000000000..d35a3c5f6f89
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AddSubscriptionResponseSurrogate.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct AddSubscriptionResponseSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public bool Success;
+    [Id(2)]
+    public string Error;
+}
+
+[RegisterConverter]
+public sealed class AddSubscriptionResponseSurrogateConverter :
+    IConverter<AddSubscriptionResponse, AddSubscriptionResponseSurrogate>
+{
+    public AddSubscriptionResponse ConvertFromSurrogate(
+        in AddSubscriptionResponseSurrogate surrogate) =>
+        new AddSubscriptionResponse
+        {
+            RequestId = surrogate.RequestId,
+            Success = surrogate.Success,
+            Error = surrogate.Error
+        };
+
+    public AddSubscriptionResponseSurrogate ConvertToSurrogate(
+        in AddSubscriptionResponse value) =>
+        new AddSubscriptionResponseSurrogate
+        {
+            RequestId = value.RequestId,
+            Success = value.Success,
+            Error = value.Error
+        };
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentIdSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentIdSurrogate.cs
new file mode 100644
index 000000000000..ddef9e997575
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentIdSurrogate.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentIdSurrogate.cs
+
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentIdSurrogate.cs
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct AgentIdSurrogate
+{
+    [Id(0)]
+    public string Key;
+    [Id(1)]
+    public string Type;
+}
+
+[RegisterConverter]
+public sealed class AgentIdSurrogateConverter :
+    IConverter<AgentId, AgentIdSurrogate>
+{
+    public AgentId ConvertFromSurrogate(
+        in AgentIdSurrogate surrogate) =>
+        new AgentId
+        {
+            Key = surrogate.Key,
+            Type = surrogate.Type
+        };
+
+    public AgentIdSurrogate ConvertToSurrogate(
+        in AgentId value) =>
+        new AgentIdSurrogate
+        {
+            Key = value.Key,
+            Type = value.Type
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs
new file mode 100644
index 000000000000..1b1df59a91bc
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentStateSurrogate.cs
+
+using Google.Protobuf;
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct AgentStateSurrogate
+{
+    [Id(0)]
+    public string Id;
+    [Id(1)]
+    public string TextData;
+    [Id(2)]
+    public ByteString BinaryData;
+    [Id(3)]
+    public AgentId AgentId;
+    [Id(4)]
+    public string Etag;
+    [Id(5)]
+    public ByteString ProtoData;
+}
+
+[RegisterConverter]
+public sealed class AgentStateSurrogateConverter :
+    IConverter<AgentState, AgentStateSurrogate>
+{
+    public AgentState ConvertFromSurrogate(
+        in AgentStateSurrogate surrogate)
+        {
+            var agentState = new AgentState
+            {
+                AgentId = surrogate.AgentId,
+                BinaryData = surrogate.BinaryData,
+                TextData = surrogate.TextData,
+                ETag = surrogate.Etag
+            };
+            //agentState.ProtoData = surrogate.ProtoData;
+            return agentState;
+        }
+        
+
+    public AgentStateSurrogate ConvertToSurrogate(
+        in AgentState value) =>
+        new AgentStateSurrogate
+        {
+            AgentId = value.AgentId,
+            BinaryData = value.BinaryData,
+            TextData = value.TextData,
+            Etag = value.ETag,
+            //ProtoData = value.ProtoData.Value
+        };
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/CloudEventSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/CloudEventSurrogate.cs
new file mode 100644
index 000000000000..7572ec3c31a3
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/CloudEventSurrogate.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// CloudEventSurrogate.cs
+
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+// TODO: Add the rest of the properties
+[GenerateSerializer]
+public struct CloudEventSurrogate
+{
+    [Id(0)]
+    public string Id;
+    [Id(1)]
+    public string TextData;
+    [Id(2)]
+    public ByteString BinaryData;
+    [Id(3)]
+    public Any ProtoData;
+}
+
+[RegisterConverter]
+public sealed class CloudEventSurrogateConverter :
+    IConverter<CloudEvent, CloudEventSurrogate>
+{
+    public CloudEvent ConvertFromSurrogate(
+        in CloudEventSurrogate surrogate) =>
+        new CloudEvent
+        {
+            TextData = surrogate.TextData,
+            BinaryData = surrogate.BinaryData,
+            Id = surrogate.Id
+        };
+
+    public CloudEventSurrogate ConvertToSurrogate(
+        in CloudEvent value) =>
+        new CloudEventSurrogate
+        {
+            TextData = value.TextData,
+            BinaryData = value.BinaryData,
+            Id = value.Id,
+            ProtoData = value.ProtoData
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs
new file mode 100644
index 000000000000..5d8b6fd25a03
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// RegisterAgentTypeRequestSurrogate.cs
+
+using Google.Protobuf.Collections;
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct RegisterAgentTypeRequestSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public string Type;
+    [Id(2)]
+    public RepeatedField<string> Events;
+    [Id(3)]
+    public RepeatedField<string> Topics;
+}
+
+[RegisterConverter]
+public sealed class RegisterAgentTypeRequestSurrogateConverter :
+    IConverter<RegisterAgentTypeRequest, RegisterAgentTypeRequestSurrogate>
+{
+    public RegisterAgentTypeRequest ConvertFromSurrogate(
+        in RegisterAgentTypeRequestSurrogate surrogate)
+    {
+        var request = new RegisterAgentTypeRequest()
+        {
+            RequestId = surrogate.RequestId,
+            Type = surrogate.Type
+        };
+        request.Events.Add(surrogate.Events);
+        request.Topics.Add(surrogate.Topics);
+        return request;
+    }
+
+    public RegisterAgentTypeRequestSurrogate ConvertToSurrogate(
+        in RegisterAgentTypeRequest value) =>
+        new RegisterAgentTypeRequestSurrogate
+        {
+            RequestId = value.RequestId,
+            Type = value.Type,
+            Events = value.Events,
+            Topics = value.Topics
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeResponseSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeResponseSurrogate.cs
new file mode 100644
index 000000000000..6fa73e5e8c3e
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeResponseSurrogate.cs
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// RegisterAgentTypeResponseSurrogate.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct RegisterAgentTypeResponseSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public bool Success;
+    [Id(2)]
+    public string Error;
+}
+
+[RegisterConverter]
+public sealed class RegisterAgentTypeResponseSurrogateConverter :
+    IConverter<RegisterAgentTypeResponse, RegisterAgentTypeResponseSurrogate>
+{
+    public RegisterAgentTypeResponse ConvertFromSurrogate(
+        in RegisterAgentTypeResponseSurrogate surrogate) =>
+        new RegisterAgentTypeResponse
+        {
+            RequestId = surrogate.RequestId,
+            Success = surrogate.Success,
+            Error = surrogate.Error
+        };
+
+    public RegisterAgentTypeResponseSurrogate ConvertToSurrogate(
+        in RegisterAgentTypeResponse value) =>
+        new RegisterAgentTypeResponseSurrogate
+        {
+            RequestId = value.RequestId,
+            Success = value.Success,
+            Error = value.Error
+        };
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcRequestSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcRequestSurrogate.cs
new file mode 100644
index 000000000000..9791a68d7952
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcRequestSurrogate.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// RpcRequestSurrogate.cs
+
+using Google.Protobuf.Collections;
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct RpcRequestSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public AgentId Source;
+    [Id(2)]
+    public AgentId Target;
+    [Id(3)]
+    public string Method;
+    [Id(4)]
+    public Payload Payload;
+    [Id(5)]
+    public MapField<string, string> Metadata;
+}
+
+[RegisterConverter]
+public sealed class RpcRequestSurrogateConverter :
+    IConverter<RpcRequest, RpcRequestSurrogate>
+{
+    public RpcRequest ConvertFromSurrogate(
+        in RpcRequestSurrogate surrogate) =>
+    new RpcRequest
+    {
+        RequestId = surrogate.RequestId,
+        Source = surrogate.Source,
+        Target = surrogate.Target,
+        Method = surrogate.Method,
+        Payload = surrogate.Payload,
+        Metadata = { surrogate.Metadata }
+    };
+
+    public RpcRequestSurrogate ConvertToSurrogate(
+        in RpcRequest value) =>
+        new RpcRequestSurrogate
+        {
+            RequestId = value.RequestId,
+            Source = value.Source,
+            Target = value.Target,
+            Method = value.Method,
+            Payload = value.Payload,
+            Metadata = value.Metadata
+        };
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcResponseSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcResponseSurrogate.cs
new file mode 100644
index 000000000000..e5f9fff66405
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RpcResponseSurrogate.cs
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// RpcResponseSurrogate.cs
+
+using Google.Protobuf.Collections;
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct RpcResponseSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public Payload Payload;
+    [Id(2)]
+    public string Error;
+    [Id(3)]
+    public MapField<string, string> Metadata;
+}
+
+[RegisterConverter]
+public sealed class RpcResponseurrogateConverter :
+    IConverter<RpcResponse, RpcResponseSurrogate>
+{
+    public RpcResponse ConvertFromSurrogate(
+        in RpcResponseSurrogate surrogate) =>
+    new RpcResponse
+    {
+        RequestId = surrogate.RequestId,
+        Payload = surrogate.Payload,
+        Error = surrogate.Error,
+        Metadata = { surrogate.Metadata }
+    };
+
+    public RpcResponseSurrogate ConvertToSurrogate(
+        in RpcResponse value) =>
+        new RpcResponseSurrogate
+        {
+            RequestId = value.RequestId,
+            Payload = value.Payload,
+            Error = value.Error,
+            Metadata = value.Metadata
+        };
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs
new file mode 100644
index 000000000000..c5427d7bf972
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// TypePrefixSubscription.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct TypePrefixSubscriptionSurrogate
+{
+    [Id(0)]
+    public string TopicTypePrefix;
+    [Id(1)]
+    public string AgentType;
+}
+
+[RegisterConverter]
+public sealed class TypePrefixSubscriptionConverter :
+    IConverter<TypePrefixSubscription, TypePrefixSubscriptionSurrogate>
+{
+    public TypePrefixSubscription ConvertFromSurrogate(
+        in TypePrefixSubscriptionSurrogate surrogate) =>
+        new TypePrefixSubscription
+        {
+            TopicTypePrefix = surrogate.TopicTypePrefix,
+            AgentType = surrogate.AgentType
+        };
+
+    public TypePrefixSubscriptionSurrogate ConvertToSurrogate(
+        in TypePrefixSubscription value) =>
+        new TypePrefixSubscriptionSurrogate
+        {
+            TopicTypePrefix = value.TopicTypePrefix,
+            AgentType = value.AgentType
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs
new file mode 100644
index 000000000000..df38462d044a
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs
@@ -0,0 +1,36 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// TypeSubscription.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct TypeSubscriptionSurrogate
+{
+    [Id(0)]
+    public string TopicType;
+    [Id(1)]
+    public string AgentType;
+}
+
+[RegisterConverter]
+public sealed class TypeSubscriptionSurrogateConverter :
+    IConverter<TypeSubscription, TypeSubscriptionSurrogate>
+{
+    public TypeSubscription ConvertFromSurrogate(
+        in TypeSubscriptionSurrogate surrogate) =>
+        new TypeSubscription
+        {
+            TopicType = surrogate.TopicType,
+            AgentType = surrogate.AgentType
+        };
+
+    public TypeSubscriptionSurrogate ConvertToSurrogate(
+        in TypeSubscription value) =>
+        new TypeSubscriptionSurrogate
+        {
+            TopicType = value.TopicType,
+            AgentType = value.AgentType
+        };
+}

From 0ac819cda4b7eee1098161530ae1fc23a765c926 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 17 Dec 2024 15:17:20 -0800
Subject: [PATCH 003/110] worker changes

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 86 +++++++++++++------
 .../Services/Grpc/GrpcWorkerConnection.cs     | 15 ++--
 2 files changed, 66 insertions(+), 35 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 146e7a8e257d..aba3f7ff8dcc 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -100,31 +100,26 @@ public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(Registe
             };
         }
     }
-    public async ValueTask BroadcastEvent(CloudEvent evt)
+    public async ValueTask<AddSubscriptionResponse> AddSubscriptionAsync(AddSubscriptionRequest request)
     {
-        var tasks = new List<Task>(_workers.Count);
-        foreach (var (_, connection) in _supportedAgentTypes)
+        try
         {
-
-            tasks.Add(this.SendMessageAsync((IConnection)connection[0], evt, default));
+            await _gatewayRegistry.SubscribeAsync(request).ConfigureAwait(true);
+            return new AddSubscriptionResponse
+            {
+                Success = true,
+                RequestId = request.RequestId
+            };
         }
-        await Task.WhenAll(tasks).ConfigureAwait(false);
-    }
-    //intetionally not static so can be called by some methods implemented in base class
-    public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
-    {
-        var queue = (GrpcWorkerConnection)connection;
-        await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
-    }
-    private void DispatchResponse(GrpcWorkerConnection connection, RpcResponse response)
-    {
-        if (!_pendingRequests.TryRemove((connection, response.RequestId), out var completion))
+        catch (Exception ex)
         {
-            _logger.LogWarning("Received response for unknown request.");
-            return;
+            return new AddSubscriptionResponse
+            {
+                Success = false,
+                RequestId = request.RequestId,
+                Error = ex.Message
+            };
         }
-        // Complete the request.
-        completion.SetResult(response);
     }
     protected override async Task ExecuteAsync(CancellationToken stoppingToken)
     {
@@ -149,6 +144,49 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
             _logger.LogWarning(exception, "Error removing worker from registry.");
         }
     }
+    internal async Task<string> ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
+    {
+        _logger.LogInformation("Received new connection from {Peer}.", context.Peer);
+        var workerProcess = new GrpcWorkerConnection(this, requestStream, responseStream, context);
+        var connectionId = Guid.NewGuid().ToString();
+        _workers[workerProcess] = workerProcess;
+        _workersByConnection[connectionId] = workerProcess;
+
+        var completion = new TaskCompletionSource<Task>();
+        var _ = Task.Run(() =>
+        {
+            completion.SetResult(workerProcess.Connect());
+        });
+        
+        await completion.Task;
+        return connectionId;
+    }
+    public async ValueTask BroadcastEvent(CloudEvent evt)
+    {
+        var tasks = new List<Task>(_workers.Count);
+        foreach (var (_, connection) in _supportedAgentTypes)
+        {
+
+            tasks.Add(this.SendMessageAsync((IConnection)connection[0], evt, default));
+        }
+        await Task.WhenAll(tasks).ConfigureAwait(false);
+    }
+    //intetionally not static so can be called by some methods implemented in base class
+    public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
+    {
+        var queue = (GrpcWorkerConnection)connection;
+        await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
+    }
+    private void DispatchResponse(GrpcWorkerConnection connection, RpcResponse response)
+    {
+        if (!_pendingRequests.TryRemove((connection, response.RequestId), out var completion))
+        {
+            _logger.LogWarning("Received response for unknown request.");
+            return;
+        }
+        // Complete the request.
+        completion.SetResult(response);
+    }
     //new is intentional...
     internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Message message)
     {
@@ -309,13 +347,7 @@ private static async Task InvokeRequestDelegate(GrpcWorkerConnection connection,
             await connection.ResponseStream.WriteAsync(new Message { Response = new RpcResponse { RequestId = request.RequestId, Error = ex.Message } }).ConfigureAwait(false);
         }
     }
-    internal Task ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
-    {
-        _logger.LogInformation("Received new connection from {Peer}.", context.Peer);
-        var workerProcess = new GrpcWorkerConnection(this, requestStream, responseStream, context);
-        _workers[workerProcess] = workerProcess;
-        return workerProcess.Completion;
-    }
+
     internal void OnRemoveWorkerProcess(GrpcWorkerConnection workerProcess)
     {
         _workers.TryRemove(workerProcess, out _);
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs
index 315cd81feb1c..00c777953688 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs
@@ -10,14 +10,14 @@ namespace Microsoft.AutoGen.Runtime.Grpc;
 internal sealed class GrpcWorkerConnection : IAsyncDisposable, IConnection
 {
     private static long s_nextConnectionId;
-    private readonly Task _readTask;
-    private readonly Task _writeTask;
+    private Task _readTask = Task.CompletedTask;
+    private Task _writeTask = Task.CompletedTask;
     private readonly string _connectionId = Interlocked.Increment(ref s_nextConnectionId).ToString();
     private readonly object _lock = new();
     private readonly HashSet<string> _supportedTypes = [];
     private readonly GrpcGateway _gateway;
     private readonly CancellationTokenSource _shutdownCancellationToken = new();
-
+    public Task Completion { get; private set; } = Task.CompletedTask;
     public GrpcWorkerConnection(GrpcGateway agentWorker, IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
     {
         _gateway = agentWorker;
@@ -25,7 +25,9 @@ public GrpcWorkerConnection(GrpcGateway agentWorker, IAsyncStreamReader<Message>
         ResponseStream = responseStream;
         ServerCallContext = context;
         _outboundMessages = Channel.CreateUnbounded<Message>(new UnboundedChannelOptions { AllowSynchronousContinuations = true, SingleReader = true, SingleWriter = false });
-
+    }
+    public Task Connect()
+    {
         var didSuppress = false;
         if (!ExecutionContext.IsFlowSuppressed())
         {
@@ -46,7 +48,7 @@ public GrpcWorkerConnection(GrpcGateway agentWorker, IAsyncStreamReader<Message>
             }
         }
 
-        Completion = Task.WhenAll(_readTask, _writeTask);
+        return Completion = Task.WhenAll(_readTask, _writeTask);
     }
 
     public IAsyncStreamReader<Message> RequestStream { get; }
@@ -75,9 +77,6 @@ public async Task SendMessage(Message message)
     {
         await _outboundMessages.Writer.WriteAsync(message).ConfigureAwait(false);
     }
-
-    public Task Completion { get; }
-
     public async Task RunReadPump()
     {
         await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);

From dfc62d4be1d0740aa024e22991d7ed0894fd73eb Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 17 Dec 2024 15:48:07 -0800
Subject: [PATCH 004/110] wip

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 168 ++++++++++--------
 1 file changed, 90 insertions(+), 78 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index aba3f7ff8dcc..7442dbb0fae5 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -24,6 +24,7 @@ public sealed class GrpcGateway : BackgroundService, IGateway
     internal readonly ConcurrentDictionary<string, GrpcWorkerConnection> _workersByConnection = new();
     private readonly ConcurrentDictionary<string, Subscription> _subscriptionsByAgentType = new();
     private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
+    private readonly ISubscriptionsGrain _subscriptions;
 
     // The mapping from agent id to worker process.
     private readonly ConcurrentDictionary<(string Type, string Key), GrpcWorkerConnection> _agentDirectory = new();
@@ -36,6 +37,7 @@ public GrpcGateway(IClusterClient clusterClient, ILogger<GrpcGateway> logger)
         _clusterClient = clusterClient;
         _reference = clusterClient.CreateObjectReference<IGateway>(this);
         _gatewayRegistry = clusterClient.GetGrain<IRegistryGrain>(0);
+        _subscriptions = clusterClient.GetGrain<ISubscriptionsGrain>(0);
     }
     public async ValueTask<RpcResponse> InvokeRequest(RpcRequest request, CancellationToken cancellationToken = default)
     {
@@ -161,33 +163,10 @@ internal async Task<string> ConnectToWorkerProcess(IAsyncStreamReader<Message> r
         await completion.Task;
         return connectionId;
     }
-    public async ValueTask BroadcastEvent(CloudEvent evt)
-    {
-        var tasks = new List<Task>(_workers.Count);
-        foreach (var (_, connection) in _supportedAgentTypes)
-        {
-
-            tasks.Add(this.SendMessageAsync((IConnection)connection[0], evt, default));
-        }
-        await Task.WhenAll(tasks).ConfigureAwait(false);
-    }
-    //intetionally not static so can be called by some methods implemented in base class
-    public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
+    internal async Task SendMessageAsync(GrpcWorkerConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
-        var queue = (GrpcWorkerConnection)connection;
-        await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
-    }
-    private void DispatchResponse(GrpcWorkerConnection connection, RpcResponse response)
-    {
-        if (!_pendingRequests.TryRemove((connection, response.RequestId), out var completion))
-        {
-            _logger.LogWarning("Received response for unknown request.");
-            return;
-        }
-        // Complete the request.
-        completion.SetResult(response);
+        await connection.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
     }
-    //new is intentional...
     internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Message message)
     {
         _logger.LogInformation("Received message {Message} from connection {Connection}.", message, connection);
@@ -214,48 +193,22 @@ internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Mess
                 break;
         };
     }
-    private async ValueTask RespondBadRequestAsync(GrpcWorkerConnection connection, string error)
-    {
-        throw new RpcException(new Status(StatusCode.InvalidArgument, error));
-    }
-
-    // agentype:rpc_request={requesting_agent_id}
-    // {genttype}:rpc_response={request_id}
-    private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, AddSubscriptionRequest request)
+    private void DispatchResponse(GrpcWorkerConnection connection, RpcResponse response)
     {
-        var topic = "";
-        var agentType = "";
-        if (request.Subscription.TypePrefixSubscription is not null)
-        {
-            topic = request.Subscription.TypePrefixSubscription.TopicTypePrefix;
-            agentType = request.Subscription.TypePrefixSubscription.AgentType;
-        }
-        else if (request.Subscription.TypeSubscription is not null)
+        if (!_pendingRequests.TryRemove((connection, response.RequestId), out var completion))
         {
-            topic = request.Subscription.TypeSubscription.TopicType;
-            agentType = request.Subscription.TypeSubscription.AgentType;
+            _logger.LogWarning("Received response for unknown request id: {RequestId}.", response.RequestId);   
+            return;
         }
-        _subscriptionsByAgentType[agentType] = request.Subscription;
-        _subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
-        await _subscriptions.SubscribeAsync(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);
+        // Complete the request.
+        completion.SetResult(response);
     }
     private async ValueTask RegisterAgentTypeAsync(GrpcWorkerConnection connection, RegisterAgentTypeRequest msg)
     {
         connection.AddSupportedType(msg.Type);
         _supportedAgentTypes.GetOrAdd(msg.Type, _ => []).Add(connection);
 
-        await _gatewayRegistry.RegisterAgentType(msg.Type, _reference).ConfigureAwait(true);
+        await _gatewayRegistry.RegisterAgentType(msg, _reference).ConfigureAwait(true);
         Message response = new()
         {
             RegisterAgentTypeResponse = new()
@@ -269,12 +222,25 @@ private async ValueTask RegisterAgentTypeAsync(GrpcWorkerConnection connection,
     }
     private async ValueTask DispatchEventAsync(CloudEvent evt)
     {
+
+        var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
+        //intentionally blocking
+        var targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
+        if (targetAgentTypes.Count == 0)
+        {
+            _logger.LogWarning("No agents found registered for event {Event}.", evt);
+        }
+        else
+        {
+            await DispatchEventToAgentsAsync(targetAgentTypes, evt).ConfigureAwait(false);
+        }
+        // alternate path    
         // get the event type and then send to all agents that are subscribed to that event type
         var eventType = evt.Type;
         // ensure that we get agentTypes as an async enumerable list - try to get the value of agentTypes by topic and then cast it to an async enumerable list
         if (_subscriptionsByTopic.TryGetValue(eventType, out var agentTypes))
         {
-            await DispatchEventToAgentsAsync(agentTypes, evt);
+            await DispatchEventToAgentsAsync(agentTypes, evt: evt).ConfigureAwait(false);
         }
         // instead of an exact match, we can also check for a prefix match where key starts with the eventType
         else if (_subscriptionsByTopic.Keys.Any(key => key.StartsWith(eventType)))
@@ -295,21 +261,6 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
             _logger.LogWarning("No agent types found for event type {EventType}.", eventType);
         }
     }
-    private async ValueTask DispatchEventToAgentsAsync(IEnumerable<string> agentTypes, CloudEvent evt)
-    {
-        var tasks = new List<Task>(agentTypes.Count());
-        foreach (var agentType in agentTypes)
-        {
-            if (_supportedAgentTypes.TryGetValue(agentType, out var connections))
-            {
-                foreach (var connection in connections)
-                {
-                    tasks.Add(this.SendMessageAsync(connection, evt));
-                }
-            }
-        }
-        await Task.WhenAll(tasks).ConfigureAwait(false);
-    }
     private async ValueTask DispatchRequestAsync(GrpcWorkerConnection connection, RpcRequest request)
     {
         var requestId = request.RequestId;
@@ -330,10 +281,8 @@ await InvokeRequestDelegate(connection, request, async request =>
             }
             // Forward the message to the gateway and return the result.
             return await gateway.InvokeRequest(request).ConfigureAwait(true);
-        });
-        //}
+        }).ConfigureAwait(false);
     }
-
     private static async Task InvokeRequestDelegate(GrpcWorkerConnection connection, RpcRequest request, Func<RpcRequest, Task<RpcResponse>> func)
     {
         try
@@ -347,7 +296,6 @@ private static async Task InvokeRequestDelegate(GrpcWorkerConnection connection,
             await connection.ResponseStream.WriteAsync(new Message { Response = new RpcResponse { RequestId = request.RequestId, Error = ex.Message } }).ConfigureAwait(false);
         }
     }
-
     internal void OnRemoveWorkerProcess(GrpcWorkerConnection workerProcess)
     {
         _workers.TryRemove(workerProcess, out _);
@@ -368,13 +316,77 @@ internal void OnRemoveWorkerProcess(GrpcWorkerConnection workerProcess)
             }
         }
     }
+    private static 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 = "";
+        var agentType = "";
+        if (request.Subscription.TypePrefixSubscription is not null)
+        {
+            topic = request.Subscription.TypePrefixSubscription.TopicTypePrefix;
+            agentType = request.Subscription.TypePrefixSubscription.AgentType;
+        }
+        else if (request.Subscription.TypeSubscription is not null)
+        {
+            topic = request.Subscription.TypeSubscription.TopicType;
+            agentType = request.Subscription.TypeSubscription.AgentType;
+        }
+        _subscriptionsByAgentType[agentType] = request.Subscription;
+        _subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
+        await _subscriptions.SubscribeAsync(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 DispatchEventToAgentsAsync(IEnumerable<string> agentTypes, CloudEvent evt)
+    {
+        var tasks = new List<Task>(agentTypes.Count());
+        foreach (var agentType in agentTypes)
+        {
+            if (_supportedAgentTypes.TryGetValue(agentType, out var connections))
+            {
+                foreach (var connection in connections)
+                {
+                    tasks.Add(this.SendMessageAsync(connection, evt));
+                }
+            }
+        }
+        await Task.WhenAll(tasks).ConfigureAwait(false);
+    }
+
     async ValueTask<RpcResponse> IGateway.InvokeRequest(RpcRequest request)
     {
         return await this.InvokeRequest(request).ConfigureAwait(false);
     }
+    public async ValueTask BroadcastEvent(CloudEvent evt)
+    {
+        var tasks = new List<Task>(_workers.Count);
+        foreach (var (_, connection) in _supportedAgentTypes)
+        {
 
+            tasks.Add(this.SendMessageAsync((IConnection)connection[0], evt, default));
+        }
+        await Task.WhenAll(tasks).ConfigureAwait(false);
+    }
     Task IGateway.SendMessageAsync(IConnection connection, CloudEvent cloudEvent)
     {
         return this.SendMessageAsync(connection, cloudEvent);
     }
+        public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
+    {
+        var queue = (GrpcWorkerConnection)connection;
+        await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
+    }
 }

From 70d488c2888ee40fb36d54b31482a37ab2c43275 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 18 Dec 2024 08:19:29 -0800
Subject: [PATCH 005/110] proto updates

---
 .../Runtime.Grpc/Services/Orleans/AgentsRegistry.cs        | 2 +-
 protos/agent_worker.proto                                  | 7 +++++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
index 30cd40ad35a4..6bee9bb1b246 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
@@ -5,7 +5,7 @@
 using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
-internal sealed class AgentsRegistry([PersistentState("state", "AgentStateStore")] IPersistentState<AgentsRegistryState> state) : Grain, IGrainRegistry
+internal sealed class AgentsRegistry([PersistentState("state", "AgentStateStore")] IPersistentState<AgentsRegistryState> state) : Grain, IRegistryGrain
 {
     // TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively.
     private readonly Dictionary<IGateway, WorkerState> _workerStates = new();
diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index 7e658699b47e..c5c5d40121c7 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -50,6 +50,13 @@ message Event {
 message RegisterAgentTypeRequest {
     string request_id = 1;
     string type = 2;
+
+message RegisterAgentTypeRequest {
+    string request_id = 1;
+    string type = 2;
+    repeated string events = 3;
+    repeated string topics = 4;
+}
 }
 
 message RegisterAgentTypeResponse {

From 22946a0d446b789b7d6f17ed28e18565e8ea2ee0 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 18 Dec 2024 08:56:50 -0800
Subject: [PATCH 006/110] registry grain cleanup

---
 .../Abstractions/IRegistryGrain.cs            |   1 +
 .../Services/Orleans/AgentsRegistry.cs        | 225 ------------------
 .../Orleans/OrleansRuntimeHostingExtenions.cs |   1 +
 .../Services/Orleans/RegistryGrain.cs         |  98 +++++++-
 protos/agent_worker.proto                     |   5 -
 5 files changed, 92 insertions(+), 238 deletions(-)
 delete mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs
index 2f48b051b38b..6a5a8e725ecd 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistryGrain.cs
@@ -6,5 +6,6 @@ namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 /// <summary>
 /// Orleans specific interface, needed to mark the key
 /// </summary>
+[Alias("Microsoft.AutoGen.Runtime.Grpc.Abstractions.IRegistryGrain")]
 public interface IRegistryGrain : IRegistry, IGrainWithIntegerKey
 { }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
deleted file mode 100644
index 6bee9bb1b246..000000000000
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistry.cs
+++ /dev/null
@@ -1,225 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// AgentsRegistry.cs
-
-using Microsoft.AutoGen.Contracts;
-using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
-
-namespace Microsoft.AutoGen.Runtime.Grpc;
-internal sealed class AgentsRegistry([PersistentState("state", "AgentStateStore")] IPersistentState<AgentsRegistryState> state) : Grain, IRegistryGrain
-{
-    // TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively.
-    private readonly Dictionary<IGateway, WorkerState> _workerStates = new();
-    private readonly Dictionary<string, List<IGateway>> _supportedAgentTypes = [];
-    private readonly Dictionary<(string Type, string Key), IGateway> _agentDirectory = [];
-    private readonly TimeSpan _agentTimeout = TimeSpan.FromMinutes(1);
-
-    public override Task OnActivateAsync(CancellationToken cancellationToken)
-    {
-        this.RegisterGrainTimer(static state => state.PurgeInactiveWorkers(), this, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
-        return base.OnActivateAsync(cancellationToken);
-    }
-
-    public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType)
-    {
-        // get all agent types that are subscribed to the topic
-        var subscribedAgents = state.State.TopicToAgentTypesMap[topic];
-        // get all agent types that are handling the event
-        var handlingAgents = state.State.EventsToAgentTypesMap[eventType];
-        // return the intersection of the two sets
-        return new(subscribedAgents.Intersect(handlingAgents).ToList());
-    }
-    public ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId)
-    {
-        // TODO: Clarify the logic
-        bool isNewPlacement;
-        if (!_agentDirectory.TryGetValue((agentId.Type, agentId.Key), out var worker) || !_workerStates.ContainsKey(worker))
-        {
-            worker = GetCompatibleWorkerCore(agentId.Type);
-            if (worker is not null)
-            {
-                // New activation.
-                _agentDirectory[(agentId.Type, agentId.Key)] = worker;
-                isNewPlacement = true;
-            }
-            else
-            {
-                // No activation, and failed to place.
-                isNewPlacement = false;
-            }
-        }
-        else
-        {
-            // Existing activation.
-            isNewPlacement = false;
-        }
-        return new((worker, isNewPlacement));
-    }
-    public ValueTask RemoveWorker(IGateway worker)
-    {
-        if (_workerStates.Remove(worker, out var state))
-        {
-            foreach (var type in state.SupportedTypes)
-            {
-                if (_supportedAgentTypes.TryGetValue(type, out var workers))
-                {
-                    workers.Remove(worker);
-                }
-            }
-        }
-        return ValueTask.CompletedTask;
-    }
-    public async ValueTask RegisterAgentType(RegisterAgentTypeRequest registration, IGateway worker)
-    {
-        if (!_supportedAgentTypes.TryGetValue(registration.Type, out var supportedAgentTypes))
-        {
-            supportedAgentTypes = _supportedAgentTypes[registration.Type] = [];
-        }
-
-        if (!supportedAgentTypes.Contains(worker))
-        {
-            supportedAgentTypes.Add(worker);
-        }
-
-        var workerState = GetOrAddWorker(worker);
-        workerState.SupportedTypes.Add(registration.Type);
-        state.State.AgentsToEventsMap[registration.Type] = new HashSet<string>(registration.Events);
-        state.State.AgentsToTopicsMap[registration.Type] = new HashSet<string>(registration.Topics);
-
-        // construct the inverse map for topics and agent types
-        foreach (var topic in registration.Topics)
-        {
-            if (!state.State.TopicToAgentTypesMap.TryGetValue(topic, out var topicSet))
-            {
-                topicSet = new HashSet<string>();
-                state.State.TopicToAgentTypesMap[topic] = topicSet;
-            }
-
-            topicSet.Add(registration.Type);
-        }
-
-        // construct the inverse map for events and agent types
-        foreach (var evt in registration.Events)
-        {
-            if (!state.State.EventsToAgentTypesMap.TryGetValue(evt, out var eventSet))
-            {
-                eventSet = new HashSet<string>();
-                state.State.EventsToAgentTypesMap[evt] = eventSet;
-            }
-
-            eventSet.Add(registration.Type);
-        }
-        await state.WriteStateAsync().ConfigureAwait(false);
-    }
-    public ValueTask AddWorker(IGateway worker)
-    {
-        GetOrAddWorker(worker);
-        return ValueTask.CompletedTask;
-    }
-    public ValueTask UnregisterAgentType(string type, IGateway worker)
-    {
-        if (_workerStates.TryGetValue(worker, out var state))
-        {
-            state.SupportedTypes.Remove(type);
-        }
-
-        if (_supportedAgentTypes.TryGetValue(type, out var workers))
-        {
-            workers.Remove(worker);
-        }
-        return ValueTask.CompletedTask;
-    }
-    private Task PurgeInactiveWorkers()
-    {
-        foreach (var (worker, state) in _workerStates)
-        {
-            if (DateTimeOffset.UtcNow - state.LastSeen > _agentTimeout)
-            {
-                _workerStates.Remove(worker);
-                foreach (var type in state.SupportedTypes)
-                {
-                    if (_supportedAgentTypes.TryGetValue(type, out var workers))
-                    {
-                        workers.Remove(worker);
-                    }
-                }
-            }
-        }
-
-        return Task.CompletedTask;
-    }
-
-    private WorkerState GetOrAddWorker(IGateway worker)
-    {
-        if (!_workerStates.TryGetValue(worker, out var workerState))
-        {
-            workerState = _workerStates[worker] = new();
-        }
-
-        workerState.LastSeen = DateTimeOffset.UtcNow;
-        return workerState;
-    }
-
-    public ValueTask<IGateway?> GetCompatibleWorker(string type) => new(GetCompatibleWorkerCore(type));
-
-    private IGateway? GetCompatibleWorkerCore(string type)
-    {
-        if (_supportedAgentTypes.TryGetValue(type, out var workers))
-        {
-            // Return a random compatible worker.
-            return workers[Random.Shared.Next(workers.Count)];
-        }
-
-        return null;
-    }
-
-    public async ValueTask SubscribeAsync(AddSubscriptionRequest sub)
-    {
-        switch (sub.Subscription.SubscriptionCase)
-        {
-            case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
-                break;
-            case Subscription.SubscriptionOneofCase.TypeSubscription:
-                {
-                    // add the topic to the set of topics for the agent type
-                    state.State.AgentsToTopicsMap.TryGetValue(sub.Subscription.TypeSubscription.AgentType, out var topics);
-                    if (topics is null)
-                    {
-                        topics = new HashSet<string>();
-                        state.State.AgentsToTopicsMap[sub.Subscription.TypeSubscription.AgentType] = topics;
-                    }
-                    topics.Add(sub.Subscription.TypeSubscription.TopicType);
-
-                    // add the agent type to the set of agent types for the topic
-                    state.State.TopicToAgentTypesMap.TryGetValue(sub.Subscription.TypeSubscription.TopicType, out var agents);
-                    if (agents is null)
-                    {
-                        agents = new HashSet<string>();
-                        state.State.TopicToAgentTypesMap[sub.Subscription.TypeSubscription.TopicType] = agents;
-                    }
-
-                    agents.Add(sub.Subscription.TypeSubscription.AgentType);
-
-                    break;
-                }
-            default:
-                throw new InvalidOperationException("Invalid subscription type");
-        }
-        await state.WriteStateAsync().ConfigureAwait(false);
-    }
-    public async ValueTask UnsubscribeAsync(AddSubscriptionRequest request)
-    {
-        throw new NotImplementedException();
-    }
-
-    public ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType)
-    {
-        throw new NotImplementedException();
-    }
-
-    private sealed class WorkerState
-    {
-        public HashSet<string> SupportedTypes { get; set; } = [];
-        public DateTimeOffset LastSeen { get; set; }
-    }
-}
-
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
index 4b8a290df031..68e0c7af745c 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
@@ -3,6 +3,7 @@
 
 using System.Configuration;
 using Microsoft.AspNetCore.Builder;
+using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index 8de1618c6002..d2b03e9e7e43 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -2,10 +2,10 @@
 // RegistryGrain.cs
 
 using Microsoft.AutoGen.Contracts;
+using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
-
-internal sealed class RegistryGrain : Grain, IRegistryGrain
+internal sealed class RegistryGrain([PersistentState("state", "AgentStateStore")] IPersistentState<AgentsRegistryState> state) : Grain, IRegistryGrain
 {
     // TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively.
     private readonly Dictionary<IGateway, WorkerState> _workerStates = new();
@@ -18,9 +18,19 @@ public override Task OnActivateAsync(CancellationToken cancellationToken)
         this.RegisterGrainTimer(static state => state.PurgeInactiveWorkers(), this, TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
         return base.OnActivateAsync(cancellationToken);
     }
+
+    public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType)
+    {
+        // get all agent types that are subscribed to the topic
+        var subscribedAgents = state.State.TopicToAgentTypesMap[topic];
+        // get all agent types that are handling the event
+        var handlingAgents = state.State.EventsToAgentTypesMap[eventType];
+        // return the intersection of the two sets
+        return new(subscribedAgents.Intersect(handlingAgents).ToList());
+    }
     public ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId)
     {
-        // TODO: 
+        // TODO: Clarify the logic
         bool isNewPlacement;
         if (!_agentDirectory.TryGetValue((agentId.Type, agentId.Key), out var worker) || !_workerStates.ContainsKey(worker))
         {
@@ -58,20 +68,47 @@ public ValueTask RemoveWorker(IGateway worker)
         }
         return ValueTask.CompletedTask;
     }
-    public ValueTask RegisterAgentType(string type, IGateway worker)
+    public async ValueTask RegisterAgentType(RegisterAgentTypeRequest registration, IGateway worker)
     {
-        if (!_supportedAgentTypes.TryGetValue(type, out var supportedAgentTypes))
+        if (!_supportedAgentTypes.TryGetValue(registration.Type, out var supportedAgentTypes))
         {
-            supportedAgentTypes = _supportedAgentTypes[type] = [];
+            supportedAgentTypes = _supportedAgentTypes[registration.Type] = [];
         }
 
         if (!supportedAgentTypes.Contains(worker))
         {
             supportedAgentTypes.Add(worker);
         }
+
         var workerState = GetOrAddWorker(worker);
-        workerState.SupportedTypes.Add(type);
-        return ValueTask.CompletedTask;
+        workerState.SupportedTypes.Add(registration.Type);
+        state.State.AgentsToEventsMap[registration.Type] = new HashSet<string>(registration.Events);
+        state.State.AgentsToTopicsMap[registration.Type] = new HashSet<string>(registration.Topics);
+
+        // construct the inverse map for topics and agent types
+        foreach (var topic in registration.Topics)
+        {
+            if (!state.State.TopicToAgentTypesMap.TryGetValue(topic, out var topicSet))
+            {
+                topicSet = new HashSet<string>();
+                state.State.TopicToAgentTypesMap[topic] = topicSet;
+            }
+
+            topicSet.Add(registration.Type);
+        }
+
+        // construct the inverse map for events and agent types
+        foreach (var evt in registration.Events)
+        {
+            if (!state.State.EventsToAgentTypesMap.TryGetValue(evt, out var eventSet))
+            {
+                eventSet = new HashSet<string>();
+                state.State.EventsToAgentTypesMap[evt] = eventSet;
+            }
+
+            eventSet.Add(registration.Type);
+        }
+        await state.WriteStateAsync().ConfigureAwait(false);
     }
     public ValueTask AddWorker(IGateway worker)
     {
@@ -135,9 +172,54 @@ private WorkerState GetOrAddWorker(IGateway worker)
         return null;
     }
 
+    public async ValueTask SubscribeAsync(AddSubscriptionRequest sub)
+    {
+        switch (sub.Subscription.SubscriptionCase)
+        {
+            case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
+                break;
+            case Subscription.SubscriptionOneofCase.TypeSubscription:
+                {
+                    // add the topic to the set of topics for the agent type
+                    state.State.AgentsToTopicsMap.TryGetValue(sub.Subscription.TypeSubscription.AgentType, out var topics);
+                    if (topics is null)
+                    {
+                        topics = new HashSet<string>();
+                        state.State.AgentsToTopicsMap[sub.Subscription.TypeSubscription.AgentType] = topics;
+                    }
+                    topics.Add(sub.Subscription.TypeSubscription.TopicType);
+
+                    // add the agent type to the set of agent types for the topic
+                    state.State.TopicToAgentTypesMap.TryGetValue(sub.Subscription.TypeSubscription.TopicType, out var agents);
+                    if (agents is null)
+                    {
+                        agents = new HashSet<string>();
+                        state.State.TopicToAgentTypesMap[sub.Subscription.TypeSubscription.TopicType] = agents;
+                    }
+
+                    agents.Add(sub.Subscription.TypeSubscription.AgentType);
+
+                    break;
+                }
+            default:
+                throw new InvalidOperationException("Invalid subscription type");
+        }
+        await state.WriteStateAsync().ConfigureAwait(false);
+    }
+    public async ValueTask UnsubscribeAsync(AddSubscriptionRequest request)
+    {
+        throw new NotImplementedException();
+    }
+
+    public ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType)
+    {
+        throw new NotImplementedException();
+    }
+
     private sealed class WorkerState
     {
         public HashSet<string> SupportedTypes { get; set; } = [];
         public DateTimeOffset LastSeen { get; set; }
     }
 }
+
diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index c5c5d40121c7..bddf34897300 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -47,17 +47,12 @@ message Event {
     map<string, string> metadata = 5;
 }
 
-message RegisterAgentTypeRequest {
-    string request_id = 1;
-    string type = 2;
-
 message RegisterAgentTypeRequest {
     string request_id = 1;
     string type = 2;
     repeated string events = 3;
     repeated string topics = 4;
 }
-}
 
 message RegisterAgentTypeResponse {
     string request_id = 1;

From 43ed890af75aec0e4458ffe794ae6913a8f59e94 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 19 Dec 2024 15:38:16 -0800
Subject: [PATCH 007/110] core services build

---
 README.md                                     |   2 +-
 dotnet/AutoGen.sln                            |  12 +-
 dotnet/samples/Hello/HelloAgent/Program.cs    |  15 +--
 dotnet/samples/Hello/HelloAgent/README.md     |   2 +-
 .../samples/Hello/HelloAgentState/Program.cs  |   2 +-
 .../samples/Hello/HelloAgentState/README.md   |   2 +-
 .../Agents/AIAgent/SKAiAgent.cs               |   2 +-
 .../IOAgent/ConsoleAgent/ConsoleAgent.cs      |   2 +-
 .../IOAgent/ConsoleAgent/IHandleConsole.cs    |   8 +-
 .../Core.Grpc/GrpcAgentWorker.cs              |   6 +-
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 102 ++++++++-------
 .../Microsoft.AutoGen/Core/AgentExtensions.cs |   4 +-
 .../Microsoft.AutoGen/Core/AgentMessenger.cs  | 123 ------------------
 .../Core/AgentMessengerFactory.cs             |  12 --
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs |   4 +-
 dotnet/src/Microsoft.AutoGen/Core/Client.cs   |   6 +-
 .../Microsoft.AutoGen/Core/IAgentWorker.cs    |   1 +
 .../Core/IAgentWorkerExtensions.cs            | 101 ++++++++++++++
 dotnet/src/Microsoft.AutoGen/Core/IHandle.cs  |  20 ++-
 .../Core/TopicSubscriptionAttribute.cs        |   2 +-
 .../Core/UninitializedAgentWorker.cs          |  20 +++
 .../Services/Grpc/GrpcGatewayService.cs       |  11 +-
 .../GrpcGatewayServiceTests.cs                |  23 +---
 ...icrosoft.AutoGen.Runtime.Grpc.Tests.csproj |   2 +-
 protos/agent_worker.proto                     |   2 +
 25 files changed, 246 insertions(+), 240 deletions(-)
 delete mode 100644 dotnet/src/Microsoft.AutoGen/Core/AgentMessenger.cs
 delete mode 100644 dotnet/src/Microsoft.AutoGen/Core/AgentMessengerFactory.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Core/IAgentWorkerExtensions.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs

diff --git a/README.md b/README.md
index 96362f2af084..4b5fd029e5b8 100644
--- a/README.md
+++ b/README.md
@@ -187,7 +187,7 @@ await app.WaitForShutdownAsync();
 [TopicSubscription("agents")]
 public class HelloAgent(
     IAgentContext worker,
-    [FromKeyedServices("EventTypes")] EventTypes typeRegistry) : ConsoleAgent(
+    [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : ConsoleAgent(
         worker,
         typeRegistry),
         ISayHello,
diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index aaeb45125ac4..fd4e048eebae 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -144,7 +144,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.AgentHost
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Runtime.Grpc.Tests", "test\Microsoft.AutoGen.Runtime.Grpc.Tests\Microsoft.AutoGen.Runtime.Grpc.Tests.csproj", "{0E7983BB-2602-421E-8B37-332E52870A10}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.Tests.Shared", "test\Microsoft.Autogen.Tests.Shared\Microsoft.Autogen.Tests.Shared.csproj", "{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Tests.Shared", "test\Microsoft.AutoGen.Tests.Shared\Microsoft.AutoGen.Tests.Shared.csproj", "{14F90F79-580E-454D-BA7A-ED6D9723020D}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -380,10 +380,10 @@ Global
 		{0E7983BB-2602-421E-8B37-332E52870A10}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{0E7983BB-2602-421E-8B37-332E52870A10}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{0E7983BB-2602-421E-8B37-332E52870A10}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -450,7 +450,7 @@ Global
 		{3892C83E-7F5D-41DF-A88C-4854EAD38856} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{0E7983BB-2602-421E-8B37-332E52870A10} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
-		{6790BEFB-66E4-42D0-AE47-0EFEA8298E3D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+		{14F90F79-580E-454D-BA7A-ED6D9723020D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}
diff --git a/dotnet/samples/Hello/HelloAgent/Program.cs b/dotnet/samples/Hello/HelloAgent/Program.cs
index dee73b1a47d3..9c3a038260b7 100644
--- a/dotnet/samples/Hello/HelloAgent/Program.cs
+++ b/dotnet/samples/Hello/HelloAgent/Program.cs
@@ -18,9 +18,8 @@ namespace Hello
 {
     [TopicSubscription("agents")]
     public class HelloAgent(
-        IAgentWorker worker, IHostApplicationLifetime hostApplicationLifetime,
-        [FromKeyedServices("EventTypes")] EventTypes typeRegistry) : Agent(
-            worker,
+        IHostApplicationLifetime hostApplicationLifetime,
+        [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : Agent(
             typeRegistry),
             ISayHello,
             IHandleConsole,
@@ -28,7 +27,7 @@ public class HelloAgent(
             IHandle<ConversationClosed>,
             IHandle<Shutdown>
     {
-        public async Task Handle(NewMessageReceived item)
+        public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken)
         {
             var response = await SayHello(item.Message).ConfigureAwait(false);
             var evt = new Output { Message = response };
@@ -40,7 +39,7 @@ public async Task Handle(NewMessageReceived item)
             };
             await PublishMessageAsync(goodbye).ConfigureAwait(false);
         }
-        public async Task Handle(ConversationClosed item)
+        public async Task Handle(ConversationClosed item, CancellationToken cancellationToken)
         {
             var goodbye = $"*********************  {item.UserId} said {item.UserMessage}  ************************";
             var evt = new Output { Message = goodbye };
@@ -51,13 +50,13 @@ public async Task Handle(ConversationClosed item)
             }
         }
 
-        public async Task Handle(Shutdown item)
+        public async Task Handle(Shutdown item, CancellationToken cancellationToken)
         {
             Console.WriteLine("Shutting down...");
             hostApplicationLifetime.StopApplication();
         }
 
-        public async Task<string> SayHello(string ask)
+        public async Task<string> SayHello(string ask, CancellationToken cancellationToken = default)
         {
             var response = $"\n\n\n\n***************Hello {ask}**********************\n\n\n\n";
             return response;
@@ -65,6 +64,6 @@ public async Task<string> SayHello(string ask)
     }
     public interface ISayHello
     {
-        public Task<string> SayHello(string ask);
+        public Task<string> SayHello(string ask, CancellationToken cancellationToken = default);
     }
 }
diff --git a/dotnet/samples/Hello/HelloAgent/README.md b/dotnet/samples/Hello/HelloAgent/README.md
index 53e3d6a65eba..067f04f3c30a 100644
--- a/dotnet/samples/Hello/HelloAgent/README.md
+++ b/dotnet/samples/Hello/HelloAgent/README.md
@@ -44,7 +44,7 @@ Within that event handler you may optionally *emit* new events, which are then s
 TopicSubscription("HelloAgents")]
 public class HelloAgent(
     iAgentWorker worker,
-    [FromKeyedServices("EventTypes")] EventTypes typeRegistry) : ConsoleAgent(
+    [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : ConsoleAgent(
         worker,
         typeRegistry),
         ISayHello,
diff --git a/dotnet/samples/Hello/HelloAgentState/Program.cs b/dotnet/samples/Hello/HelloAgentState/Program.cs
index dbb16c3bbb9b..d882f1f42c4a 100644
--- a/dotnet/samples/Hello/HelloAgentState/Program.cs
+++ b/dotnet/samples/Hello/HelloAgentState/Program.cs
@@ -20,7 +20,7 @@ namespace Hello
     public class HelloAgent(
         IAgentWorker worker,
         IHostApplicationLifetime hostApplicationLifetime,
-        [FromKeyedServices("EventTypes")] EventTypes typeRegistry) : Agent(
+        [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : Agent(
             worker,
             typeRegistry),
             IHandleConsole,
diff --git a/dotnet/samples/Hello/HelloAgentState/README.md b/dotnet/samples/Hello/HelloAgentState/README.md
index f46c66df1e1d..c8fead8b23b1 100644
--- a/dotnet/samples/Hello/HelloAgentState/README.md
+++ b/dotnet/samples/Hello/HelloAgentState/README.md
@@ -44,7 +44,7 @@ Within that event handler you may optionally *emit* new events, which are then s
 TopicSubscription("HelloAgents")]
 public class HelloAgent(
     iAgentWorker worker,
-    [FromKeyedServices("EventTypes")] EventTypes typeRegistry) : ConsoleAgent(
+    [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : ConsoleAgent(
         worker,
         typeRegistry),
         ISayHello,
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs
index 1d0c57068e13..210c2054686e 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs
@@ -12,7 +12,7 @@ public abstract class SKAiAgent<T>(
     IAgentWorker worker,
     ISemanticTextMemory memory,
     Kernel kernel,
-    EventTypes typeRegistry) : Agent(
+    AgentsMetadata typeRegistry) : Agent(
         worker,
         typeRegistry) where T : class, new()
 {
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs
index 7bfe5ab8d786..03b654741704 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs
@@ -13,7 +13,7 @@ public abstract class ConsoleAgent : IOAgent,
 {
 
     // instead of the primary constructor above, make a constructr here that still calls the base constructor
-    public ConsoleAgent(IAgentWorker worker, [FromKeyedServices("EventTypes")] EventTypes typeRegistry) : base(worker, typeRegistry)
+    public ConsoleAgent(IAgentWorker worker, [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : base(worker, typeRegistry)
     {
         _route = "console";
     }
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
index 31b89453a2e6..dced31aac23a 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
@@ -12,7 +12,7 @@ public interface IHandleConsole : IHandle<Output>, IHandle<Input>
     AgentId AgentId { get; }
     ValueTask PublishMessageAsync<T>(T message, string? source = null, CancellationToken token = default) where T : IMessage;
 
-    async Task IHandle<Output>.Handle(Output item)
+    async Task IHandle<Output>.Handle(Output item, CancellationToken cancellationToken)
     {
         // Assuming item has a property `Message` that we want to write to the console
         Console.WriteLine(item.Message);
@@ -22,9 +22,9 @@ async Task IHandle<Output>.Handle(Output item)
         {
             Route = "console"
         };
-        await PublishMessageAsync(evt);
+        await PublishMessageAsync(evt).ConfigureAwait(false);
     }
-    async Task IHandle<Input>.Handle(Input item)
+    async Task IHandle<Input>.Handle(Input item, CancellationToken cancellationToken)
     {
         Console.WriteLine("Please enter input:");
         string content = Console.ReadLine() ?? string.Empty;
@@ -35,7 +35,7 @@ async Task IHandle<Input>.Handle(Input item)
         {
             Route = "console"
         };
-        await PublishMessageAsync(evt);
+        await PublishMessageAsync(evt).ConfigureAwait(false);
     }
     static Task ProcessOutput(string message)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index f96f42a2c11b..e63e2a1a5737 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -32,7 +32,7 @@ public sealed class GrpcAgentWorker(
         FullMode = BoundedChannelFullMode.Wait
     });
     private readonly AgentRpc.AgentRpcClient _client = client;
-    private readonly IServiceProvider _serviceProvider = serviceProvider;
+    public readonly IServiceProvider ServiceProvider = serviceProvider;
     private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes = configuredAgentTypes;
     private readonly ILogger<GrpcAgentWorker> _logger = logger;
     private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping);
@@ -40,6 +40,8 @@ public sealed class GrpcAgentWorker(
     private Task? _readTask;
     private Task? _writeTask;
 
+    IServiceProvider IAgentWorker.ServiceProvider => throw new NotImplementedException();
+
     public void Dispose()
     {
         _outboundMessagesChannel.Writer.TryComplete();
@@ -175,7 +177,7 @@ private Agent GetOrActivateAgent(AgentId agentId)
         {
             if (_agentTypes.TryGetValue(agentId.Type, out var agentType))
             {
-                agent = (Agent)ActivatorUtilities.CreateInstance(_serviceProvider, agentType, this);
+                agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType, this);
                 _agents.TryAdd((agentId.Type, agentId.Key), agent);
             }
             else
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 67905ecb0543..d986df40add9 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -16,7 +16,7 @@ namespace Microsoft.AutoGen.Core;
 /// <summary>
 /// Represents the base class for an agent in the AutoGen system.
 /// </summary>
-public abstract class Agent : IHandle
+public abstract class Agent
 {
     private readonly object _lock = new();
     private readonly ConcurrentDictionary<string, TaskCompletionSource<RpcResponse>> _pendingRequests = [];
@@ -32,23 +32,25 @@ public abstract class Agent : IHandle
     public AgentId AgentId { get; private set; }
     private readonly Channel<object> _mailbox = Channel.CreateUnbounded<object>();
     protected internal ILogger<Agent> _logger;
-    public AgentMessenger Messenger { get; private set; }
+    public IAgentWorker Worker { get; private set; }
     private readonly ConcurrentDictionary<Type, MethodInfo> _handlersByMessageType;
-    internal Task Completion { get; private set; }
+    protected readonly AgentsMetadata EventTypes;
 
-    protected readonly EventTypes EventTypes;
-
-    protected Agent(IAgentWorker worker,
-        EventTypes eventTypes,
+    protected Agent(
+        AgentsMetadata eventTypes,
         ILogger<Agent>? logger = null)
     {
         EventTypes = eventTypes;
         AgentId = new AgentId(this.GetType().Name, new Guid().ToString());
         _logger = logger ?? LoggerFactory.Create(builder => { }).CreateLogger<Agent>();
         _handlersByMessageType = new(GetType().GetHandlersLookupTable());
-        Messenger = AgentMessengerFactory.Create(worker, DistributedContextPropagator.Current);
         AddImplicitSubscriptionsAsync().AsTask().Wait();
-        Completion = Start();
+        Worker = new UninitializedAgentWorker();
+    }
+    public Task Initialize(IAgentWorker worker)
+    {
+        Worker = worker;
+        return Start();
     }
 
     private async ValueTask AddImplicitSubscriptionsAsync()
@@ -74,7 +76,7 @@ private async ValueTask AddImplicitSubscriptionsAsync()
                 }
             };
             // explicitly wait for this to complete
-            await Messenger.SendMessageAsync(new Message { AddSubscriptionRequest = subscriptionRequest }).ConfigureAwait(true);
+            await Worker.SendMessageAsync(new Message { AddSubscriptionRequest = subscriptionRequest }).ConfigureAwait(true);
         }
 
         // using reflection, find all methods that Handle<T> and subscribe to the topic T
@@ -82,10 +84,13 @@ private async ValueTask AddImplicitSubscriptionsAsync()
         foreach (var method in handleMethods)
         {
             var eventType = method.GetParameters()[0].ParameterType;
-            var topic = EventTypes.EventsMap.FirstOrDefault(x => x.Value.Contains(eventType.Name)).Key;
-            if (topic != null)
+            var topics = (IAsyncEnumerable<string>?)EventTypes.GetTopicsForAgent(GetType());
+            if (topics != null)
             {
-                Subscribe(nameof(topic));
+                await foreach (var topic in topics.ConfigureAwait(false))
+                {
+                    Subscribe(topic);
+                }
             }
         }
 
@@ -148,7 +153,7 @@ protected internal async Task HandleRpcMessage(Message msg, CancellationToken ca
                 {
                     var activity = this.ExtractActivity(msg.CloudEvent.Type, msg.CloudEvent.Attributes);
                     await this.InvokeWithActivityAsync(
-                        static ((Agent Agent, CloudEvent Item) state, CancellationToken _) => state.Agent.CallHandler(state.Item),
+                        static ((Agent Agent, CloudEvent Item) state, CancellationToken _) => state.Agent.CallHandlerAsync(state.Item),
                         (this, msg.CloudEvent),
                         activity,
                         msg.CloudEvent.Type, cancellationToken).ConfigureAwait(false);
@@ -186,18 +191,18 @@ public List<string> Subscribe(string topic)
                 }
             }
         };
-        Messenger.SendMessageAsync(message).AsTask().Wait();
+        Worker.SendMessageAsync(message).AsTask().Wait();
 
         return new List<string> { topic };
     }
     public async Task StoreAsync(AgentState state, CancellationToken cancellationToken = default)
     {
-        await Messenger.StoreAsync(state, cancellationToken).ConfigureAwait(false);
+        await Worker.StoreAsync(state, cancellationToken).ConfigureAwait(false);
         return;
     }
     public async Task<T> ReadAsync<T>(AgentId agentId, CancellationToken cancellationToken = default) where T : IMessage, new()
     {
-        var agentstate = await Messenger.ReadAsync(agentId, cancellationToken).ConfigureAwait(false);
+        var agentstate = await Worker.ReadAsync(agentId, cancellationToken).ConfigureAwait(false);
         return agentstate.FromAgentState<T>();
     }
     private void OnResponseCore(RpcResponse response)
@@ -226,7 +231,9 @@ private async Task OnRequestCoreAsync(RpcRequest request, CancellationToken canc
         {
             response = new RpcResponse { Error = ex.Message };
         }
-        await Messenger.SendResponseAsync(request, response, cancellationToken).ConfigureAwait(false);
+        response.RequestId = request.RequestId;
+
+        await Worker.SendResponseAsync(response, cancellationToken).ConfigureAwait(false);
     }
 
     protected async Task<RpcResponse> RequestAsync(AgentId target, string method, Dictionary<string, string> parameters)
@@ -250,7 +257,7 @@ protected async Task<RpcResponse> RequestAsync(AgentId target, string method, Di
         activity?.SetTag("peer.service", target.ToString());
 
         var completion = new TaskCompletionSource<RpcResponse>(TaskCreationOptions.RunContinuationsAsynchronously);
-        Messenger!.Update(request, activity);
+        IAgentWorkerExtensions.Update(this.Worker, request, activity);
         await this.InvokeWithActivityAsync(
             static async (state, ct) =>
             {
@@ -258,7 +265,7 @@ static async (state, ct) =>
 
                 self._pendingRequests.AddOrUpdate(request.RequestId, _ => completion, (_, __) => completion);
 
-                await state.Item1.Messenger!.SendRequestAsync(state.Item1, state.request, ct).ConfigureAwait(false);
+                await state.Item1.Worker!.SendRequestAsync(state.Item1, state.request, ct).ConfigureAwait(false);
 
                 await completion.Task.ConfigureAwait(false);
             },
@@ -283,53 +290,54 @@ public async ValueTask PublishEventAsync(CloudEvent item, CancellationToken canc
         activity?.SetTag("peer.service", $"{item.Type}/{item.Source}");
 
         // TODO: fix activity
-        Messenger.Update(item, activity);
+        IAgentWorkerExtensions.Update(this.Worker, item, activity);
         await this.InvokeWithActivityAsync(
             static async ((Agent Agent, CloudEvent Event) state, CancellationToken ct) =>
             {
-                await state.Agent.Messenger.PublishEventAsync(state.Event).ConfigureAwait(false);
+                await state.Agent.Worker.PublishEventAsync(state.Event).ConfigureAwait(false);
             },
             (this, item),
             activity,
             item.Type, cancellationToken).ConfigureAwait(false);
     }
 
-    public Task CallHandler(CloudEvent item)
+    public Task CallHandlerAsync(CloudEvent item)
     {
         // Only send the event to the handler if the agent type is handling that type
-        // foreach of the keys in the EventTypes.EventsMap[] if it contains the item.type
-        foreach (var key in EventTypes.EventsMap.Keys)
+        if (EventTypes.CheckIfTypeHandles(GetType(), eventName: item.Type))
         {
-            if (EventTypes.EventsMap[key].Contains(item.Type))
+            var payload = item.ProtoData.Unpack(EventTypes.TypeRegistry);
+            var eventType = EventTypes.GetEventTypeByName(item.Type);
+            if (eventType == null)
             {
-                var payload = item.ProtoData.Unpack(EventTypes.TypeRegistry);
-                var convertedPayload = Convert.ChangeType(payload, EventTypes.Types[item.Type]);
-                var genericInterfaceType = typeof(IHandle<>).MakeGenericType(EventTypes.Types[item.Type]);
+                _logger.LogError($"Event type {item.Type} not found in the registry");
+                return Task.CompletedTask;
+            }
+            var convertedPayload = Convert.ChangeType(payload, eventType);
+            var genericInterfaceType = typeof(IHandle<>).MakeGenericType(eventType);
 
-                MethodInfo methodInfo;
-                try
+            MethodInfo methodInfo;
+            try
+            {
+                // check that our target actually implements this interface, otherwise call the default static
+                if (genericInterfaceType.IsAssignableFrom(this.GetType()))
                 {
-                    // check that our target actually implements this interface, otherwise call the default static
-                    if (genericInterfaceType.IsAssignableFrom(this.GetType()))
-                    {
-                        methodInfo = genericInterfaceType.GetMethod(nameof(IHandle<object>.Handle), BindingFlags.Public | BindingFlags.Instance)
-                                       ?? throw new InvalidOperationException($"Method not found on type {genericInterfaceType.FullName}");
-                        return methodInfo.Invoke(this, [payload]) as Task ?? Task.CompletedTask;
-                    }
-                    else
-                    {
-                        // The error here is we have registered for an event that we do not have code to listen to
-                        throw new InvalidOperationException($"No handler found for event '{item.Type}'; expecting IHandle<{item.Type}> implementation.");
-                    }
+                    methodInfo = genericInterfaceType.GetMethod(nameof(IHandle<IMessage>.Handle), BindingFlags.Public | BindingFlags.Instance)
+                                    ?? throw new InvalidOperationException($"Method not found on type {genericInterfaceType.FullName}");
+                    return methodInfo.Invoke(this, [payload]) as Task ?? Task.CompletedTask;
                 }
-                catch (Exception ex)
+                else
                 {
-                    _logger.LogError(ex, $"Error invoking method {nameof(IHandle<object>.Handle)}");
-                    throw; // TODO: ?
+                    // The error here is we have registered for an event that we do not have code to listen to
+                    throw new InvalidOperationException($"Agent Type '{GetType()}' is registered to handle this type but no handler found for event '{item.Type}'; expecting IHandle<{item.Type}> implementation.");
                 }
             }
+            catch (Exception ex)
+            {
+                _logger.LogError(ex, $"Error invoking method {nameof(IHandle<IMessage>.Handle)}");
+                throw; // TODO: ?
+            }
         }
-
         return Task.CompletedTask;
     }
 
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentExtensions.cs
index 911107f784c5..50d25b20ada4 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentExtensions.cs
@@ -22,7 +22,7 @@ public static class AgentExtensions
     public static Activity? ExtractActivity(this Agent agent, string activityName, IDictionary<string, string> metadata)
     {
         Activity? activity;
-        var (traceParent, traceState) = agent.Messenger.GetTraceIdAndState(metadata);
+        (string? traceParent, string? traceState) = IAgentWorkerExtensions.GetTraceIdAndState(agent.Worker, metadata);
         if (!string.IsNullOrEmpty(traceParent))
         {
             if (ActivityContext.TryParse(traceParent, traceState, isRemote: true, out var parentContext))
@@ -43,7 +43,7 @@ public static class AgentExtensions
                     activity.TraceStateString = traceState;
                 }
 
-                var baggage = agent.Messenger.ExtractMetadata(metadata);
+                var baggage = IAgentWorkerExtensions.ExtractMetadata(agent.Worker, metadata);
 
                 foreach (var baggageItem in baggage)
                 {
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentMessenger.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentMessenger.cs
deleted file mode 100644
index 66b1c0c65da9..000000000000
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentMessenger.cs
+++ /dev/null
@@ -1,123 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// AgentMessenger.cs
-
-using System.Diagnostics;
-using Google.Protobuf.Collections;
-using Microsoft.AutoGen.Contracts;
-using static Microsoft.AutoGen.Contracts.CloudEvent.Types;
-
-namespace Microsoft.AutoGen.Core;
-
-public sealed class AgentMessenger(IAgentWorker worker, DistributedContextPropagator distributedContextPropagator)
-{
-    private readonly IAgentWorker worker = worker;
-
-    private DistributedContextPropagator DistributedContextPropagator { get; } = distributedContextPropagator;
-    public (string?, string?) GetTraceIdAndState(IDictionary<string, string> metadata)
-    {
-        DistributedContextPropagator.ExtractTraceIdAndState(metadata,
-            static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
-            {
-                var metadata = (IDictionary<string, string>)carrier!;
-                fieldValues = null;
-                metadata.TryGetValue(fieldName, out fieldValue);
-            },
-            out var traceParent,
-            out var traceState);
-        return (traceParent, traceState);
-    }
-    public (string?, string?) GetTraceIdAndState(MapField<string, CloudEventAttributeValue> metadata)
-    {
-        DistributedContextPropagator.ExtractTraceIdAndState(metadata,
-            static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
-            {
-                var metadata = (MapField<string, CloudEventAttributeValue>)carrier!;
-                fieldValues = null;
-                metadata.TryGetValue(fieldName, out var ceValue);
-                fieldValue = ceValue?.CeString;
-            },
-            out var traceParent,
-            out var traceState);
-        return (traceParent, traceState);
-    }
-    public void Update(RpcRequest request, Activity? activity = null)
-    {
-        DistributedContextPropagator.Inject(activity, request.Metadata, static (carrier, key, value) =>
-        {
-            var metadata = (IDictionary<string, string>)carrier!;
-            if (metadata.TryGetValue(key, out _))
-            {
-                metadata[key] = value;
-            }
-            else
-            {
-                metadata.Add(key, value);
-            }
-        });
-    }
-    public void Update(CloudEvent cloudEvent, Activity? activity = null)
-    {
-        DistributedContextPropagator.Inject(activity, cloudEvent.Attributes, static (carrier, key, value) =>
-        {
-            var mapField = (MapField<string, CloudEventAttributeValue>)carrier!;
-            if (mapField.TryGetValue(key, out var ceValue))
-            {
-                mapField[key] = new CloudEventAttributeValue { CeString = value };
-            }
-            else
-            {
-                mapField.Add(key, new CloudEventAttributeValue { CeString = value });
-            }
-        });
-    }
-    public async ValueTask SendResponseAsync(RpcRequest request, RpcResponse response, CancellationToken cancellationToken = default)
-    {
-        response.RequestId = request.RequestId;
-        await worker.SendResponseAsync(response, cancellationToken).ConfigureAwait(false);
-    }
-    public async ValueTask SendRequestAsync(Agent agent, RpcRequest request, CancellationToken cancellationToken = default)
-    {
-        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);
-    }
-    public async ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default)
-    {
-        await worker.StoreAsync(value, cancellationToken).ConfigureAwait(false);
-    }
-    public ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default)
-    {
-        return worker.ReadAsync(agentId, cancellationToken);
-    }
-
-    public IDictionary<string, string> ExtractMetadata(IDictionary<string, string> metadata)
-    {
-        var baggage = DistributedContextPropagator.ExtractBaggage(metadata, static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
-        {
-            var metadata = (IDictionary<string, string>)carrier!;
-            fieldValues = null;
-            metadata.TryGetValue(fieldName, out fieldValue);
-        });
-
-        return baggage as IDictionary<string, string> ?? new Dictionary<string, string>();
-    }
-
-    public IDictionary<string, string> ExtractMetadata(MapField<string, CloudEventAttributeValue> metadata)
-    {
-        var baggage = DistributedContextPropagator.ExtractBaggage(metadata, static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
-        {
-            var metadata = (MapField<string, CloudEventAttributeValue>)carrier!;
-            fieldValues = null;
-            metadata.TryGetValue(fieldName, out var ceValue);
-            fieldValue = ceValue?.CeString;
-        });
-
-        return baggage as IDictionary<string, string> ?? new Dictionary<string, string>();
-    }
-}
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentMessengerFactory.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentMessengerFactory.cs
deleted file mode 100644
index c008f9f2d5aa..000000000000
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentMessengerFactory.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// AgentMessengerFactory.cs
-
-using System.Diagnostics;
-namespace Microsoft.AutoGen.Core;
-public class AgentMessengerFactory()
-{
-    public static AgentMessenger Create(IAgentWorker worker, DistributedContextPropagator distributedContextPropagator)
-    {
-        return new AgentMessenger(worker, distributedContextPropagator);
-    }
-}
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 3b70461a39fd..7531429da2ed 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -22,7 +22,7 @@ public class AgentWorker(
     private readonly ConcurrentDictionary<string, AgentState> _agentStates = new();
     private readonly ConcurrentDictionary<string, (Agent Agent, string OriginalRequestId)> _pendingClientRequests = new();
     private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping);
-    private readonly IServiceProvider _serviceProvider = serviceProvider;
+    public IServiceProvider ServiceProvider { get; } = serviceProvider;
     private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes = configuredAgentTypes;
     private readonly ConcurrentDictionary<string, Subscription> _subscriptionsByAgentType = new();
     private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
@@ -182,7 +182,7 @@ private Agent GetOrActivateAgent(AgentId agentId)
         {
             if (_agentTypes.TryGetValue(agentId.Type, out var agentType))
             {
-                agent = (Agent)ActivatorUtilities.CreateInstance(_serviceProvider, agentType, this);
+                agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType, this);
                 _agents.TryAdd((agentId.Type, agentId.Key), agent);
             }
             else
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Client.cs b/dotnet/src/Microsoft.AutoGen/Core/Client.cs
index 1d523005fedf..d93aca292ded 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Client.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Client.cs
@@ -3,7 +3,7 @@
 using Microsoft.Extensions.DependencyInjection;
 
 namespace Microsoft.AutoGen.Core;
-public sealed class Client(IAgentWorker worker, [FromKeyedServices("EventTypes")] EventTypes eventTypes)
-    : Agent(worker, eventTypes)
+public sealed class Client([FromKeyedServices("EventTypes")] AgentsMetadata eventTypes)
+    : Agent(eventTypes)
 {
-}
+}
\ No newline at end of file
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
index f26e30584ca6..13e18cf6f8d0 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
@@ -5,6 +5,7 @@ namespace Microsoft.AutoGen.Core;
 
 public interface IAgentWorker
 {
+    IServiceProvider ServiceProvider { get; }
     ValueTask PublishEventAsync(CloudEvent evt, CancellationToken cancellationToken = default);
     ValueTask SendRequestAsync(Agent agent, RpcRequest request, CancellationToken cancellationToken = default);
     ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default);
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorkerExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorkerExtensions.cs
new file mode 100644
index 000000000000..53dd8890e974
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorkerExtensions.cs
@@ -0,0 +1,101 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// IAgentWorkerExtensions.cs
+
+using System.Diagnostics;
+using Google.Protobuf.Collections;
+using Microsoft.AutoGen.Contracts;
+using Microsoft.Extensions.DependencyInjection;
+using static Microsoft.AutoGen.Contracts.CloudEvent.Types;
+
+namespace Microsoft.AutoGen.Core;
+
+public static class IAgentWorkerExtensions
+{
+    public static (string?, string?) GetTraceIdAndState(IAgentWorker worker, IDictionary<string, string> metadata)
+    {
+        var dcp = worker.ServiceProvider.GetRequiredService<DistributedContextPropagator>();
+        dcp.ExtractTraceIdAndState(metadata,
+            static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
+            {
+                var metadata = (IDictionary<string, string>)carrier!;
+                fieldValues = null;
+                metadata.TryGetValue(fieldName, out fieldValue);
+            },
+            out var traceParent,
+            out var traceState);
+        return (traceParent, traceState);
+    }
+    public static (string?, string?) GetTraceIdAndState(IAgentWorker worker, MapField<string, CloudEventAttributeValue> metadata)
+    {
+        var dcp = worker.ServiceProvider.GetRequiredService<DistributedContextPropagator>();
+        dcp.ExtractTraceIdAndState(metadata,
+            static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
+            {
+                var metadata = (MapField<string, CloudEventAttributeValue>)carrier!;
+                fieldValues = null;
+                metadata.TryGetValue(fieldName, out var ceValue);
+                fieldValue = ceValue?.CeString;
+            },
+            out var traceParent,
+            out var traceState);
+        return (traceParent, traceState);
+    }
+    public static void Update(IAgentWorker worker, RpcRequest request, Activity? activity = null)
+    {
+        var dcp = worker.ServiceProvider.GetRequiredService<DistributedContextPropagator>();
+        dcp.Inject(activity, request.Metadata, static (carrier, key, value) =>
+        {
+            var metadata = (IDictionary<string, string>)carrier!;
+            if (metadata.TryGetValue(key, out _))
+            {
+                metadata[key] = value;
+            }
+            else
+            {
+                metadata.Add(key, value);
+            }
+        });
+    }
+    public static void Update(IAgentWorker worker, CloudEvent cloudEvent, Activity? activity = null)
+    {
+        var dcp = worker.ServiceProvider.GetRequiredService<DistributedContextPropagator>();
+        dcp.Inject(activity, cloudEvent.Attributes, static (carrier, key, value) =>
+        {
+            var mapField = (MapField<string, CloudEventAttributeValue>)carrier!;
+            if (mapField.TryGetValue(key, out var ceValue))
+            {
+                mapField[key] = new CloudEventAttributeValue { CeString = value };
+            }
+            else
+            {
+                mapField.Add(key, new CloudEventAttributeValue { CeString = value });
+            }
+        });
+    }
+
+    public static IDictionary<string, string> ExtractMetadata(IAgentWorker worker, IDictionary<string, string> metadata)
+    {
+        var dcp = worker.ServiceProvider.GetRequiredService<DistributedContextPropagator>();
+        var baggage = dcp.ExtractBaggage(metadata, static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
+        {
+            var metadata = (IDictionary<string, string>)carrier!;
+            fieldValues = null;
+            metadata.TryGetValue(fieldName, out fieldValue);
+        });
+
+        return baggage as IDictionary<string, string> ?? new Dictionary<string, string>();
+    }
+    public static IDictionary<string, string> ExtractMetadata(IAgentWorker worker, MapField<string, CloudEventAttributeValue> metadata)
+    {
+        var dcp = worker.ServiceProvider.GetRequiredService<DistributedContextPropagator>();
+        var baggage = dcp.ExtractBaggage(metadata, static (object? carrier, string fieldName, out string? fieldValue, out IEnumerable<string>? fieldValues) =>
+        {
+            var metadata = (MapField<string, CloudEventAttributeValue>)carrier!;
+            fieldValues = null;
+            metadata.TryGetValue(fieldName, out var ceValue);
+            fieldValue = ceValue?.CeString;
+        });
+
+        return baggage as IDictionary<string, string> ?? new Dictionary<string, string>();
+    }
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs b/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
index 025ea8a5149c..25f7aea89e9b 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
@@ -1,12 +1,20 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // IHandle.cs
+
+using Google.Protobuf;
+
 namespace Microsoft.AutoGen.Core;
-public interface IHandle
-{
-    Task HandleObject(object item);
-}
 
-public interface IHandle<T> : IHandle
+/// <summary>
+/// Defines a handler interface for processing items of type <typeparamref name="T"/>.
+/// </summary>
+/// <typeparam name="T">The type of item to be handled, which must implement <see cref="IMessage"/>.</typeparam>
+public interface IHandle<in T> where T : IMessage
 {
-    Task Handle(T item);
+    /// <summary>
+    /// Handles the specified item asynchronously.
+    /// </summary>
+    /// <param name="item">The item to be handled.</param>
+    /// <returns>A task that represents the asynchronous operation.</returns>
+    Task Handle(T item, CancellationToken cancellationToken);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/TopicSubscriptionAttribute.cs b/dotnet/src/Microsoft.AutoGen/Core/TopicSubscriptionAttribute.cs
index ba17520f79b9..8c1e93e2f664 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/TopicSubscriptionAttribute.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/TopicSubscriptionAttribute.cs
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // TopicSubscriptionAttribute.cs
 
-namespace Microsoft.AutoGen.Contracts;
+namespace Microsoft.AutoGen.Core;
 
 [AttributeUsage(AttributeTargets.All)]
 public class TopicSubscriptionAttribute(string topic) : Attribute
diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
new file mode 100644
index 000000000000..6597b005c481
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// UninitializedAgentWorker.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Core;
+public class UninitializedAgentWorker() : IAgentWorker
+{
+    public IServiceProvider ServiceProvider => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    internal const string AgentNotInitializedMessage = "Agent not initialized correctly. An Agent should never be directly intialized - it is always started byt the AgentWorker from the Runtime.";
+    public ValueTask PublishEventAsync(CloudEvent evt, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask SendRequestAsync(Agent agent, RpcRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public class AgentInitalizedIncorrectlyException(string message) : Exception(message)
+    {
+    }
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index a922f23c8e70..156fab2ef191 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -34,7 +34,6 @@ public override async Task<GetStateResponse> GetState(AgentId request, ServerCal
         var state = await Gateway.ReadAsync(request);
         return new GetStateResponse { AgentState = state };
     }
-
     public override async Task<SaveStateResponse> SaveState(AgentState request, ServerCallContext context)
     {
         await Gateway.StoreAsync(request);
@@ -43,4 +42,14 @@ public override async Task<SaveStateResponse> SaveState(AgentState request, Serv
             Success = true // TODO: Implement error handling
         };
     }
+    public override async Task<AddSubscriptionResponse> AddSubscription(AddSubscriptionRequest request, ServerCallContext context)
+    {
+        request.RequestId = context.Peer;
+        return await Gateway.AddSubscriptionAsync(request);
+    }
+    public override async Task<RegisterAgentTypeResponse> RegisterAgent(RegisterAgentTypeRequest request, ServerCallContext context)
+    {
+        request.RequestId = context.Peer;
+        return await Gateway.RegisterAgentTypeAsync(request);
+    }
 }
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 507809fc3e5a..6c37c492ab33 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -46,14 +46,11 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
 
         await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-        var responseMessage = await client.ReadNext();
 
-        var connectionId = responseMessage!.OpenChannelResponse.ConnectionId;
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
 
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), connectionId), client.CallContext);
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), connectionId), client.CallContext);
-
-        var inputEvent = new NewMessageReceived { Message = $"Start-{connectionId}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
+        var inputEvent = new NewMessageReceived { Message = $"Start-{client.CallContext.Peer}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
 
         client.AddMessage(new Message { CloudEvent = inputEvent });
         var newMessageReceived = await client.ReadNext();
@@ -61,7 +58,7 @@ public async Task Test_Message_Exchange_Through_Gateway()
         newMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
 
         // Simulate an agent, by publishing a new message in the request stream
-        var helloEvent = new Hello { Message = $"Hello test-{connectionId}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
+        var helloEvent = new Hello { Message = $"Hello test-{client.CallContext.Peer}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
         client.AddMessage(new Message { CloudEvent = helloEvent });
 
         var helloMessageReceived = await client.ReadNext();
@@ -81,12 +78,9 @@ public async Task Test_Message_Goes_To_Right_Worker()
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
 
         await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-        var responseMessage = await client.ReadNext();
-
-        var connectionId = responseMessage!.OpenChannelResponse.ConnectionId;
 
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), connectionId), client.CallContext);
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), connectionId), client.CallContext);
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
+        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
 
     }
 
@@ -102,11 +96,8 @@ public async Task Test_RegisterAgent_Should_Succeed()
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
 
         await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-        var responseMessage = await client.ReadNext();
-
-        var connectionId = responseMessage!.OpenChannelResponse.ConnectionId;
 
-        var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), connectionId), client.CallContext);
+        var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         response.Success.Should().BeTrue();
     }
 
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
index 1cdeb3f295e8..23e3794606e1 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
@@ -15,7 +15,7 @@
   <ItemGroup>
     <ProjectReference Include="..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
     <ProjectReference Include="..\..\src\Microsoft.AutoGen\Runtime.Grpc\Microsoft.AutoGen.Runtime.Grpc.csproj" />
-    <ProjectReference Include="..\Microsoft.Autogen.Tests.Shared\Microsoft.Autogen.Tests.Shared.csproj" />
+    <ProjectReference Include="..\Microsoft.AutoGen.Tests.Shared\Microsoft.AutoGen.Tests.Shared.csproj" />
   </ItemGroup>
 
   <ItemGroup>
diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index bddf34897300..d962ae96acb4 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -92,6 +92,8 @@ service AgentRpc {
     rpc OpenChannel (stream Message) returns (stream Message);
     rpc GetState(AgentId) returns (GetStateResponse);
     rpc SaveState(AgentState) returns (SaveStateResponse);
+    rpc RegisterAgent(RegisterAgentTypeRequest) returns (RegisterAgentTypeResponse);
+    rpc AddSubscription(AddSubscriptionRequest) returns (AddSubscriptionResponse);
 }
 
 message AgentState {

From 98e517d35f76d391901adb38bdfdaaf8775782c7 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 19 Dec 2024 18:03:54 -0800
Subject: [PATCH 008/110] Adding AgentTests and host builder cleanup

---
 dotnet/AutoGen.sln                            | 14 ++--
 .../Core/HostBuilderExtensions.cs             | 82 +------------------
 dotnet/src/Microsoft.AutoGen/Core/IHandle.cs  |  4 +-
 .../AgentTests.cs                             | 49 +++++------
 .../Microsoft.AutoGen.Core.Tests.csproj}      |  0
 5 files changed, 32 insertions(+), 117 deletions(-)
 rename dotnet/test/{Microsoft.AutoGen.Agents.Tests => Microsoft.AutoGen.Core.Tests}/AgentTests.cs (70%)
 rename dotnet/test/{Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj => Microsoft.AutoGen.Core.Tests/Microsoft.AutoGen.Core.Tests.csproj} (100%)

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index fd4e048eebae..474371b3b85f 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -126,8 +126,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAgentState", "samples\
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AutoGen.Extensions.Aspire", "src\Microsoft.AutoGen\Extensions\Aspire\Microsoft.AutoGen.Extensions.Aspire.csproj", "{65059914-5527-4A00-9308-9FAF23D5E85A}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AutoGen.Agents.Tests", "test\Microsoft.AutoGen.Agents.Tests\Microsoft.AutoGen.Agents.Tests.csproj", "{394FDAF8-74F9-4977-94A5-3371737EB774}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Integration.Tests", "test\Microsoft.AutoGen.Integration.Tests\Microsoft.AutoGen.Integration.Tests.csproj", "{D04C6153-8EAF-4E54-9852-52CEC1BE8D31}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloAgent.AppHost", "test\Microsoft.AutoGen.Integration.Tests.AppHosts\HelloAgent.AppHost\HelloAgent.AppHost.csproj", "{99D7766B-076F-4E6F-A8D2-3DF1DAFA2599}"
@@ -146,6 +144,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Runtime.G
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Tests.Shared", "test\Microsoft.AutoGen.Tests.Shared\Microsoft.AutoGen.Tests.Shared.csproj", "{14F90F79-580E-454D-BA7A-ED6D9723020D}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Tests", "test\Microsoft.AutoGen.Core.Tests\Microsoft.AutoGen.Core.Tests.csproj", "{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -344,10 +344,6 @@ Global
 		{65059914-5527-4A00-9308-9FAF23D5E85A}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{65059914-5527-4A00-9308-9FAF23D5E85A}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{65059914-5527-4A00-9308-9FAF23D5E85A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{394FDAF8-74F9-4977-94A5-3371737EB774}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{394FDAF8-74F9-4977-94A5-3371737EB774}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{394FDAF8-74F9-4977-94A5-3371737EB774}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{394FDAF8-74F9-4977-94A5-3371737EB774}.Release|Any CPU.Build.0 = Release|Any CPU
 		{D04C6153-8EAF-4E54-9852-52CEC1BE8D31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{D04C6153-8EAF-4E54-9852-52CEC1BE8D31}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{D04C6153-8EAF-4E54-9852-52CEC1BE8D31}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -384,6 +380,10 @@ Global
 		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{14F90F79-580E-454D-BA7A-ED6D9723020D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -441,7 +441,6 @@ Global
 		{97550E87-48C6-4EBF-85E1-413ABAE9DBFD} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{64EF61E7-00A6-4E5E-9808-62E10993A0E5} = {7EB336C2-7C0A-4BC8-80C6-A3173AB8DC45}
 		{65059914-5527-4A00-9308-9FAF23D5E85A} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
-		{394FDAF8-74F9-4977-94A5-3371737EB774} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{D04C6153-8EAF-4E54-9852-52CEC1BE8D31} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{99D7766B-076F-4E6F-A8D2-3DF1DAFA2599} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{7F60934B-3E59-48D0-B26D-04A39FEC13EF} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
@@ -451,6 +450,7 @@ Global
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{0E7983BB-2602-421E-8B37-332E52870A10} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{14F90F79-580E-454D-BA7A-ED6D9723020D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}
diff --git a/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
index 95d4d7ce7553..96279b46dd43 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
@@ -3,9 +3,6 @@
 
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using Google.Protobuf;
-using Google.Protobuf.Reflection;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
@@ -14,8 +11,6 @@ namespace Microsoft.AutoGen.Core;
 
 public static class HostBuilderExtensions
 {
-    private const string _defaultAgentServiceAddress = "https://localhost:53071";
-
     public static IHostApplicationBuilder AddAgent<
         [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TAgent>(this IHostApplicationBuilder builder, string typeName) where TAgent : Agent
     {
@@ -30,90 +25,21 @@ public static IHostApplicationBuilder AddAgent(this IHostApplicationBuilder buil
         return builder;
     }
 
-    public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilder builder, string? agentServiceAddress = null)
+    public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilder builder)
     {
-        agentServiceAddress ??= builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress;
+        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
         builder.Services.AddSingleton<IAgentWorker, AgentWorker>();
         builder.Services.AddSingleton<IHostedService>(sp => (IHostedService)sp.GetRequiredService<IAgentWorker>());
-        builder.Services.AddKeyedSingleton("EventTypes", (sp, key) =>
+        builder.Services.AddKeyedSingleton("AgentsMetadata", (sp, key) =>
         {
-            var interfaceType = typeof(IMessage);
-            var pairs = AppDomain.CurrentDomain.GetAssemblies()
-                                    .SelectMany(assembly => assembly.GetTypes())
-                                    .Where(type => interfaceType.IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
-                                    .Select(t => (t, GetMessageDescriptor(t)));
-
-            var descriptors = pairs.Select(t => t.Item2);
-            var typeRegistry = TypeRegistry.FromMessages(descriptors);
-            var types = pairs.ToDictionary(item => item.Item2?.FullName ?? "", item => item.t);
-
-            var eventsMap = AppDomain.CurrentDomain.GetAssemblies()
-                                    .SelectMany(assembly => assembly.GetTypes())
-                                    .Where(type => ReflectionHelper.IsSubclassOfGeneric(type, typeof(Agent)) && !type.IsAbstract)
-                                    .Select(t => (t, t.GetInterfaces()
-                                                  .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandle<>))
-                                                  .Select(i => (GetMessageDescriptor(i.GetGenericArguments().First())?.FullName ?? "")).ToHashSet()))
-                                    .ToDictionary(item => item.t, item => item.Item2);
-            // if the assembly contains any interfaces of type IHandler, then add all the methods of the interface to the eventsMap
-            var handlersMap = AppDomain.CurrentDomain.GetAssemblies()
-                                    .SelectMany(assembly => assembly.GetTypes())
-                                    .Where(type => ReflectionHelper.IsSubclassOfGeneric(type, typeof(Agent)) && !type.IsAbstract)
-                                    .Select(t => (t, t.GetMethods()
-                                                  .Where(m => m.Name == "Handle")
-                                                  .Select(m => (GetMessageDescriptor(m.GetParameters().First().ParameterType)?.FullName ?? "")).ToHashSet()))
-                                    .ToDictionary(item => item.t, item => item.Item2);
-            // get interfaces implemented by the agent and get the methods of the interface if they are named Handle
-            var ifaceHandlersMap = AppDomain.CurrentDomain.GetAssemblies()
-                                    .SelectMany(assembly => assembly.GetTypes())
-                                    .Where(type => ReflectionHelper.IsSubclassOfGeneric(type, typeof(Agent)) && !type.IsAbstract)
-                                    .Select(t => t.GetInterfaces()
-                                                  .Select(i => (t, i, i.GetMethods()
-                                                  .Where(m => m.Name == "Handle")
-                                                    .Select(m => (GetMessageDescriptor(m.GetParameters().First().ParameterType)?.FullName ?? ""))
-                                                    //to dictionary of type t and paramter type of the method
-                                                    .ToDictionary(m => m, m => m).Keys.ToHashSet())).ToList());
-            // for each item in ifaceHandlersMap, add the handlers to eventsMap with item as the key 
-            foreach (var item in ifaceHandlersMap)
-            {
-                foreach (var iface in item)
-                {
-                    if (eventsMap.TryGetValue(iface.Item2, out var events))
-                    {
-                        events.UnionWith(iface.Item3);
-                    }
-                    else
-                    {
-                        eventsMap[iface.Item2] = iface.Item3;
-                    }
-                }
-            }
-
-            // merge the handlersMap into the eventsMap
-            foreach (var item in handlersMap)
-            {
-                if (eventsMap.TryGetValue(item.Key, out var events))
-                {
-                    events.UnionWith(item.Value);
-                }
-                else
-                {
-                    eventsMap[item.Key] = item.Value;
-                }
-            }
-            return new EventTypes(typeRegistry, types, eventsMap);
+            return ReflectionHelper.GetAgentsMetadata(assemblies);
         });
         builder.Services.AddSingleton<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;
-    }
 }
 public sealed class AgentApplicationBuilder(IHostApplicationBuilder builder)
 {
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs b/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
index 25f7aea89e9b..0b91f4436d4c 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
@@ -16,5 +16,5 @@ public interface IHandle<in T> where T : IMessage
     /// </summary>
     /// <param name="item">The item to be handled.</param>
     /// <returns>A task that represents the asynchronous operation.</returns>
-    Task Handle(T item, CancellationToken cancellationToken);
-}
+    Task Handle(T item, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
similarity index 70%
rename from dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentTests.cs
rename to dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 08a88da048de..8040ab451c64 100644
--- a/dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -2,14 +2,15 @@
 // AgentTests.cs
 
 using System.Collections.Concurrent;
+using System.Diagnostics;
 using FluentAssertions;
 using Google.Protobuf.Reflection;
 using Microsoft.AspNetCore.Builder;
 using Microsoft.AutoGen.Contracts;
 using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
-using Moq;
 using Xunit;
 using static Microsoft.AutoGen.Core.Tests.AgentTests;
 
@@ -18,13 +19,22 @@ namespace Microsoft.AutoGen.Core.Tests;
 [Collection(ClusterFixtureCollection.Name)]
 public class AgentTests(InMemoryAgentRuntimeFixture fixture)
 {
+    private readonly IServiceProvider _serviceProvider = fixture.AppHost.Services;
     private readonly InMemoryAgentRuntimeFixture _fixture = fixture;
+    // need a variable to store the runtime instance
+    public static WebApplication? Host { get; private set; }
 
+    [Fact]
+    public void Agent_ShouldThrowException_WhenNotInitialized()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        agent.Subscribe("TestEvent");
+        Assert.Throws<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(() => agent.Worker.ServiceProvider);
+    }
     [Fact]
     public async Task ItInvokeRightHandlerTestAsync()
     {
-        var mockWorker = new Mock<IAgentWorker>();
-        var agent = new TestAgent(mockWorker.Object, new EventTypes(TypeRegistry.Empty, [], []), new Logger<Agent>(new LoggerFactory()));
+        var agent = new TestAgent(new AgentsMetadata(TypeRegistry.Empty, new Dictionary<string, Type>(), new Dictionary<Type, HashSet<string>>(), new Dictionary<Type, HashSet<string>>()), new Logger<Agent>(new LoggerFactory()));
 
         await agent.HandleObject("hello world");
         await agent.HandleObject(42);
@@ -58,28 +68,11 @@ await client.PublishMessageAsync(new TextMessage()
     /// <summary>
     /// The test agent is a simple agent that is used for testing purposes.
     /// </summary>
-    public class TestAgent : Agent, IHandle<string>, IHandle<int>, IHandle<TextMessage>
+    public class TestAgent(
+        [FromKeyedServices("AgentsMetadata")] AgentsMetadata eventTypes,
+        Logger<Agent>? logger = null) : Agent(eventTypes, logger), IHandle<TextMessage>
     {
-        public TestAgent(
-            IAgentWorker worker,
-            [FromKeyedServices("EventTypes")] EventTypes eventTypes,
-            Logger<Agent>? logger = null) : base(worker, eventTypes, logger)
-        {
-        }
-
-        public Task Handle(string item)
-        {
-            ReceivedItems.Add(item);
-            return Task.CompletedTask;
-        }
-
-        public Task Handle(int item)
-        {
-            ReceivedItems.Add(item);
-            return Task.CompletedTask;
-        }
-
-        public Task Handle(TextMessage item)
+        public Task Handle(TextMessage item, CancellationToken cancellationToken = default)
         {
             ReceivedMessages[item.Source] = item.TextMessage_;
             return Task.CompletedTask;
@@ -100,13 +93,9 @@ public sealed class InMemoryAgentRuntimeFixture : IDisposable
     public InMemoryAgentRuntimeFixture()
     {
         var builder = WebApplication.CreateBuilder();
-
-        // step 1: create in-memory agent runtime
-        // step 2: register TestAgent to that agent runtime
-        builder
-            .AddAgentWorker()
+        builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
+        builder.AddAgentWorker()
             .AddAgent<TestAgent>(nameof(TestAgent));
-
         AppHost = builder.Build();
         AppHost.StartAsync().Wait();
     }
diff --git a/dotnet/test/Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Core.Tests/Microsoft.AutoGen.Core.Tests.csproj
similarity index 100%
rename from dotnet/test/Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj
rename to dotnet/test/Microsoft.AutoGen.Core.Tests/Microsoft.AutoGen.Core.Tests.csproj

From ac7bde852504d9488ed71ac13ad2aa6eb9cd2696 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 19 Dec 2024 18:08:28 -0800
Subject: [PATCH 009/110] fixing what the tests found

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index d986df40add9..747762b09eef 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -44,13 +44,14 @@ protected Agent(
         AgentId = new AgentId(this.GetType().Name, new Guid().ToString());
         _logger = logger ?? LoggerFactory.Create(builder => { }).CreateLogger<Agent>();
         _handlersByMessageType = new(GetType().GetHandlersLookupTable());
-        AddImplicitSubscriptionsAsync().AsTask().Wait();
         Worker = new UninitializedAgentWorker();
     }
     public Task Initialize(IAgentWorker worker)
     {
         Worker = worker;
-        return Start();
+        var completion = Start();
+        AddImplicitSubscriptionsAsync().AsTask().Wait();
+        return completion;
     }
 
     private async ValueTask AddImplicitSubscriptionsAsync()

From 5ee0db86e3f25090dbaaabc39e5e0deb111f6a58 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 19 Dec 2024 19:47:41 -0800
Subject: [PATCH 010/110] EventTypes->AgentMetadata

---
 dotnet/src/Microsoft.AutoGen/Core/ReflectionHelper.cs | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/ReflectionHelper.cs b/dotnet/src/Microsoft.AutoGen/Core/ReflectionHelper.cs
index 41b27ffee613..a977af69e79d 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/ReflectionHelper.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/ReflectionHelper.cs
@@ -23,7 +23,7 @@ public static bool IsSubclassOfGeneric(Type type, Type genericBaseType)
         }
         return false;
     }
-    public static EventTypes GetAgentsMetadata(params Assembly[] assemblies)
+    public static AgentsMetadata GetAgentsMetadata(params Assembly[] assemblies)
     {
         var interfaceType = typeof(IMessage);
         var pairs = assemblies
@@ -42,8 +42,12 @@ public static EventTypes GetAgentsMetadata(params Assembly[] assemblies)
                                               .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandle<>))
                                               .Select(i => GetMessageDescriptor(i.GetGenericArguments().First())?.FullName ?? "").ToHashSet()))
                                 .ToDictionary(item => item.t, item => item.Item2);
-
-        return new EventTypes(typeRegistry, types, eventsMap);
+        var topicsMap = assemblies
+                               .SelectMany(assembly => assembly.GetTypes())
+                               .Where(type => IsSubclassOfGeneric(type, typeof(Agent)) && !type.IsAbstract)
+                               .Select(t => (t, t.GetCustomAttributes<TopicSubscriptionAttribute>().Select(a => a.Topic).ToHashSet()))
+                               .ToDictionary(item => item.t, item => item.Item2);
+        return new AgentsMetadata(typeRegistry, types, eventsMap, topicsMap);
     }
 
     /// <summary>

From bd6664230dbe1f98899feec475b717e0c934c2c1 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 19 Dec 2024 23:21:50 -0800
Subject: [PATCH 011/110] initialize test

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 14 ++++++-------
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs |  1 +
 .../AgentTests.cs                             | 21 +++++++++++++++++--
 3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 747762b09eef..b5d76e7f3880 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -46,12 +46,11 @@ protected Agent(
         _handlersByMessageType = new(GetType().GetHandlersLookupTable());
         Worker = new UninitializedAgentWorker();
     }
-    public Task Initialize(IAgentWorker worker)
+    public static void Initialize(IAgentWorker worker, Agent agent)
     {
-        Worker = worker;
-        var completion = Start();
-        AddImplicitSubscriptionsAsync().AsTask().Wait();
-        return completion;
+        agent.Worker = worker;
+        agent.Start().ConfigureAwait(false);
+        agent.AddImplicitSubscriptionsAsync().AsTask().Wait();
     }
 
     private async ValueTask AddImplicitSubscriptionsAsync()
@@ -85,16 +84,15 @@ private async ValueTask AddImplicitSubscriptionsAsync()
         foreach (var method in handleMethods)
         {
             var eventType = method.GetParameters()[0].ParameterType;
-            var topics = (IAsyncEnumerable<string>?)EventTypes.GetTopicsForAgent(GetType());
+            var topics = EventTypes.GetTopicsForAgent(GetType());
             if (topics != null)
             {
-                await foreach (var topic in topics.ConfigureAwait(false))
+                foreach (var topic in topics)
                 {
                     Subscribe(topic);
                 }
             }
         }
-
     }
 
     /// <summary>
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 7531429da2ed..5e578fb5ab92 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -183,6 +183,7 @@ private Agent GetOrActivateAgent(AgentId agentId)
             if (_agentTypes.TryGetValue(agentId.Type, out var agentType))
             {
                 agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType, this);
+                Agent.Initialize(this, agent);
                 _agents.TryAdd((agentId.Type, agentId.Key), agent);
             }
             else
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 8040ab451c64..f4282fe86615 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -24,13 +24,30 @@ public class AgentTests(InMemoryAgentRuntimeFixture fixture)
     // need a variable to store the runtime instance
     public static WebApplication? Host { get; private set; }
 
+    /// <summary>
+    /// Verify that if the agent is not initialized via AgentWorker, it should throw the correct exception.
+    /// </summary>
+    /// <returns>void</returns>
     [Fact]
     public void Agent_ShouldThrowException_WhenNotInitialized()
     {
         var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
-        agent.Subscribe("TestEvent");
-        Assert.Throws<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(() => agent.Worker.ServiceProvider);
+        Assert.Throws<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(() => { agent.Subscribe("TestEvent"); });
+    }
+
+    /// <summary>
+    /// validate that the agent is initialized correctly with implicit subs
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task Agent_ShouldInitializeCorrectly()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        Assert.Equal("AgentWorker", agent.Worker.GetType().Name);
     }
+
     [Fact]
     public async Task ItInvokeRightHandlerTestAsync()
     {

From 94ddacb225fb9d6c472c838125358c30501e3f01 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 20 Dec 2024 10:44:46 -0800
Subject: [PATCH 012/110] more fixes along the way

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 31 +++++++++++--------
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs |  3 +-
 dotnet/src/Microsoft.AutoGen/Core/Client.cs   |  2 +-
 .../Core/HostBuilderExtensions.cs             |  7 ++++-
 .../Core/UninitializedAgentWorker.cs          |  2 +-
 .../AgentTests.cs                             | 16 +++++++---
 6 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index b5d76e7f3880..3ce1a0039f2c 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -41,7 +41,7 @@ protected Agent(
         ILogger<Agent>? logger = null)
     {
         EventTypes = eventTypes;
-        AgentId = new AgentId(this.GetType().Name, new Guid().ToString());
+        AgentId = new AgentId(this.GetType().Name, Guid.NewGuid().ToString());
         _logger = logger ?? LoggerFactory.Create(builder => { }).CreateLogger<Agent>();
         _handlersByMessageType = new(GetType().GetHandlersLookupTable());
         Worker = new UninitializedAgentWorker();
@@ -49,8 +49,10 @@ protected Agent(
     public static void Initialize(IAgentWorker worker, Agent agent)
     {
         agent.Worker = worker;
-        agent.Start().ConfigureAwait(false);
-        agent.AddImplicitSubscriptionsAsync().AsTask().Wait();
+        agent.Start().ContinueWith(async startTask =>
+        {
+            await agent.AddImplicitSubscriptionsAsync();
+        }, TaskScheduler.Default);
     }
 
     private async ValueTask AddImplicitSubscriptionsAsync()
@@ -152,7 +154,7 @@ protected internal async Task HandleRpcMessage(Message msg, CancellationToken ca
                 {
                     var activity = this.ExtractActivity(msg.CloudEvent.Type, msg.CloudEvent.Attributes);
                     await this.InvokeWithActivityAsync(
-                        static ((Agent Agent, CloudEvent Item) state, CancellationToken _) => state.Agent.CallHandlerAsync(state.Item),
+                        static ((Agent Agent, CloudEvent Item) state, CancellationToken ct) => state.Agent.CallHandlerAsync(state.Item, ct),
                         (this, msg.CloudEvent),
                         activity,
                         msg.CloudEvent.Type, cancellationToken).ConfigureAwait(false);
@@ -300,7 +302,7 @@ static async ((Agent Agent, CloudEvent Event) state, CancellationToken ct) =>
             item.Type, cancellationToken).ConfigureAwait(false);
     }
 
-    public Task CallHandlerAsync(CloudEvent item)
+    public Task CallHandlerAsync(CloudEvent item, CancellationToken cancellationToken = default)
     {
         // Only send the event to the handler if the agent type is handling that type
         if (EventTypes.CheckIfTypeHandles(GetType(), eventName: item.Type))
@@ -323,7 +325,7 @@ public Task CallHandlerAsync(CloudEvent item)
                 {
                     methodInfo = genericInterfaceType.GetMethod(nameof(IHandle<IMessage>.Handle), BindingFlags.Public | BindingFlags.Instance)
                                     ?? throw new InvalidOperationException($"Method not found on type {genericInterfaceType.FullName}");
-                    return methodInfo.Invoke(this, [payload]) as Task ?? Task.CompletedTask;
+                    return methodInfo.Invoke(this, new object[] { convertedPayload, cancellationToken }) as Task ?? Task.CompletedTask;
                 }
                 else
                 {
@@ -342,23 +344,26 @@ public Task CallHandlerAsync(CloudEvent item)
 
     public Task<RpcResponse> HandleRequestAsync(RpcRequest request) => Task.FromResult(new RpcResponse { Error = "Not implemented" });
 
-    //TODO: should this be async and cancellable?
-    public virtual Task HandleObject(object item)
+    /// <summary>
+    /// Handles a generic object
+    /// </summary>
+    /// <param name="item">The object to handle</param>
+    /// <param name="cancellationToken">The cancellation token</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    /// TODO: this is only called from tests, should we remove it?
+    public virtual async Task HandleObjectAsync(object item, CancellationToken cancellationToken = default)
     {
         // get all Handle<T> methods
         var handleTMethods = this.GetType().GetMethods().Where(m => m.Name == "Handle" && m.GetParameters().Length == 1).ToList();
-
         // get the one that matches the type of the item
         var handleTMethod = handleTMethods.FirstOrDefault(m => m.GetParameters()[0].ParameterType == item.GetType());
-
         // if we found one, invoke it
         if (handleTMethod != null)
         {
-            return (Task)handleTMethod.Invoke(this, [item])!;
+            await (Task)handleTMethod.Invoke(this, [item])!;
         }
-
         // otherwise, complain
-        throw new InvalidOperationException($"No handler found for type {item.GetType().FullName}");
+        _logger.LogError($"No handler found for type {item.GetType().FullName}");
     }
     public async ValueTask PublishEventAsync(string topic, IMessage evt, CancellationToken cancellationToken = default)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 5e578fb5ab92..a4bbe9aa5656 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -182,9 +182,10 @@ private Agent GetOrActivateAgent(AgentId agentId)
         {
             if (_agentTypes.TryGetValue(agentId.Type, out var agentType))
             {
-                agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType, this);
+                agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType);
                 Agent.Initialize(this, agent);
                 _agents.TryAdd((agentId.Type, agentId.Key), agent);
+
             }
             else
             {
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Client.cs b/dotnet/src/Microsoft.AutoGen/Core/Client.cs
index d93aca292ded..f689751b4002 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Client.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Client.cs
@@ -3,7 +3,7 @@
 using Microsoft.Extensions.DependencyInjection;
 
 namespace Microsoft.AutoGen.Core;
-public sealed class Client([FromKeyedServices("EventTypes")] AgentsMetadata eventTypes)
+public sealed class Client([FromKeyedServices("AgentsMetadata")] AgentsMetadata eventTypes)
     : Agent(eventTypes)
 {
 }
\ No newline at end of file
diff --git a/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
index 96279b46dd43..e48195c63a6e 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
@@ -35,7 +35,12 @@ public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilde
         {
             return ReflectionHelper.GetAgentsMetadata(assemblies);
         });
-        builder.Services.AddSingleton<Client>();
+        builder.Services.AddSingleton((s) => {
+            var worker = s.GetRequiredService<IAgentWorker>();
+            var client = ActivatorUtilities.CreateInstance<Client>(s);
+            Agent.Initialize(worker, client);
+            return client;
+        });
         builder.Services.AddSingleton(new AgentApplicationBuilder(builder));
 
         return builder;
diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
index 6597b005c481..a6cb6a040d0a 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -7,7 +7,7 @@ namespace Microsoft.AutoGen.Core;
 public class UninitializedAgentWorker() : IAgentWorker
 {
     public IServiceProvider ServiceProvider => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
-    internal const string AgentNotInitializedMessage = "Agent not initialized correctly. An Agent should never be directly intialized - it is always started byt the AgentWorker from the Runtime.";
+    internal const string AgentNotInitializedMessage = "Agent not initialized correctly. An Agent should never be directly intialized - it is always started by the AgentWorker from the Runtime.";
     public ValueTask PublishEventAsync(CloudEvent evt, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index f4282fe86615..eda96fad37b8 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -53,8 +53,8 @@ public async Task ItInvokeRightHandlerTestAsync()
     {
         var agent = new TestAgent(new AgentsMetadata(TypeRegistry.Empty, new Dictionary<string, Type>(), new Dictionary<Type, HashSet<string>>(), new Dictionary<Type, HashSet<string>>()), new Logger<Agent>(new LoggerFactory()));
 
-        await agent.HandleObject("hello world");
-        await agent.HandleObject(42);
+        await agent.HandleObjectAsync("hello world");
+        await agent.HandleObjectAsync(42);
 
         agent.ReceivedItems.Should().HaveCount(2);
         agent.ReceivedItems[0].Should().Be("hello world");
@@ -65,7 +65,6 @@ public async Task ItInvokeRightHandlerTestAsync()
     public async Task ItDelegateMessageToTestAgentAsync()
     {
         var client = _fixture.AppHost.Services.GetRequiredService<Client>();
-
         await client.PublishMessageAsync(new TextMessage()
         {
             Source = nameof(ItDelegateMessageToTestAgentAsync),
@@ -94,7 +93,16 @@ public Task Handle(TextMessage item, CancellationToken cancellationToken = defau
             ReceivedMessages[item.Source] = item.TextMessage_;
             return Task.CompletedTask;
         }
-
+        public Task Handle(string item)
+        {
+            ReceivedItems.Add(item);
+            return Task.CompletedTask;
+        }
+        public Task Handle(int item)
+        {
+            ReceivedItems.Add(item);
+            return Task.CompletedTask;
+        }
         public List<object> ReceivedItems { get; private set; } = [];
 
         /// <summary>

From e3db41e40de96dd34a6295659f756aab89f4cb26 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 20 Dec 2024 10:50:59 -0800
Subject: [PATCH 013/110] improve the error for uninitialized agents

---
 dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
index a6cb6a040d0a..e89236314842 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -7,7 +7,7 @@ namespace Microsoft.AutoGen.Core;
 public class UninitializedAgentWorker() : IAgentWorker
 {
     public IServiceProvider ServiceProvider => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
-    internal const string AgentNotInitializedMessage = "Agent not initialized correctly. An Agent should never be directly intialized - it is always started by the AgentWorker from the Runtime.";
+    internal const string AgentNotInitializedMessage = "Agent not initialized correctly. An Agent should never be directly intialized - it is always started by the AgentWorker from the Runtime (using the static Initialize() method).";
     public ValueTask PublishEventAsync(CloudEvent evt, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);

From c7cf200a661ebe6d1d11d9d41a5ba3dfb6cd73ae Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 20 Dec 2024 15:41:13 -0800
Subject: [PATCH 014/110] move message extensions and update AgentWorker

---
 .../Contracts/MessageExtensions.cs            | 49 ----------
 .../Core.Grpc/GrpcAgentWorker.cs              |  5 +
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 23 +++--
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs | 88 +++++++++++++----
 .../Microsoft.AutoGen/Core/IAgentWorker.cs    |  1 +
 .../Core/MessageExtensions.cs                 | 96 +++++++++++++++++++
 .../Core/UninitializedAgentWorker.cs          |  1 +
 .../TestAgent.cs                              |  4 +-
 8 files changed, 192 insertions(+), 75 deletions(-)
 delete mode 100644 dotnet/src/Microsoft.AutoGen/Contracts/MessageExtensions.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs

diff --git a/dotnet/src/Microsoft.AutoGen/Contracts/MessageExtensions.cs b/dotnet/src/Microsoft.AutoGen/Contracts/MessageExtensions.cs
deleted file mode 100644
index c531c5b76ec3..000000000000
--- a/dotnet/src/Microsoft.AutoGen/Contracts/MessageExtensions.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// MessageExtensions.cs
-
-using Google.Protobuf;
-using Google.Protobuf.WellKnownTypes;
-
-namespace Microsoft.AutoGen.Contracts;
-
-public static class MessageExtensions
-{
-    private const string PROTO_DATA_CONTENT_TYPE = "application/x-protobuf";
-    public static CloudEvent ToCloudEvent<T>(this T message, string source) where T : IMessage
-    {
-        return new CloudEvent
-        {
-            ProtoData = Any.Pack(message),
-            Type = message.Descriptor.FullName,
-            Source = source,
-            Id = Guid.NewGuid().ToString(),
-            SpecVersion = "1.0",
-            Attributes = { { "datacontenttype", new CloudEvent.Types.CloudEventAttributeValue { CeString = PROTO_DATA_CONTENT_TYPE } } }
-        };
-    }
-    public static T FromCloudEvent<T>(this CloudEvent cloudEvent) where T : IMessage, new()
-    {
-        return cloudEvent.ProtoData.Unpack<T>();
-    }
-    public static AgentState ToAgentState<T>(this T state, AgentId agentId, string eTag) where T : IMessage
-    {
-        return new AgentState
-        {
-            ProtoData = Any.Pack(state),
-            AgentId = agentId,
-            ETag = eTag
-        };
-    }
-
-    public static T FromAgentState<T>(this AgentState state) where T : IMessage, new()
-    {
-        if (state.HasTextData == true)
-        {
-            if (typeof(T) == typeof(AgentState))
-            {
-                return (T)(IMessage)state;
-            }
-        }
-        return state.ProtoData.Unpack<T>();
-    }
-}
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index e63e2a1a5737..71209d4ed4d7 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -396,5 +396,10 @@ public async ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken
             throw new KeyNotFoundException($"Failed to read AgentState for {agentId}.");
         }
     }
+
+    public ValueTask<List<string>> GetSubscriptionsAsync(Type type)
+    {
+        throw new NotImplementedException();
+    }
 }
 
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 3ce1a0039f2c..fb7e964381c5 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -175,6 +175,10 @@ await this.InvokeWithActivityAsync(
                 break;
         }
     }
+    public async ValueTask<List<string>> GetSubscriptionsAsync()
+    {
+        return await Worker.GetSubscriptionsAsync(GetType()).ConfigureAwait(false);
+    }
     public List<string> Subscribe(string topic)
     {
         Message message = new()
@@ -277,14 +281,21 @@ static async (state, ct) =>
         // Return the result from the already-completed task
         return await completion.Task.ConfigureAwait(false);
     }
-
-    public async ValueTask PublishMessageAsync<T>(T message, string? source = null, CancellationToken token = default) where T : IMessage
+    /// <summary>
+    /// Publishes a message asynchronously.
+    /// </summary>
+    /// <typeparam name="T">The type of the message.</typeparam>
+    /// <param name="event">The message to publish.</param>
+    /// <param name="key">The source of the message.</param>
+    /// <param name="token">A token to cancel the operation.</param>
+    /// <returns>A task representing the asynchronous operation.</returns>
+    public async ValueTask PublishMessageAsync<T>(T @event, string? topic = null, string? key = null, CancellationToken token = default ) where T : IMessage
     {
-        var src = string.IsNullOrWhiteSpace(source) ? this.AgentId.Key : source;
-        var evt = message.ToCloudEvent(src);
+        var k = string.IsNullOrWhiteSpace(key) ? AgentId.Key : key;
+        var topicType = string.IsNullOrWhiteSpace(topic) ? "default" : topic;
+        var evt = @event.ToCloudEvent(k, topicType);
         await PublishEventAsync(evt, token).ConfigureAwait(false);
     }
-
     public async ValueTask PublishEventAsync(CloudEvent item, CancellationToken cancellationToken = default)
     {
         var activity = s_source.StartActivity($"PublishEventAsync '{item.Type}'", ActivityKind.Client, Activity.Current?.Context ?? default);
@@ -367,6 +378,6 @@ public virtual async Task HandleObjectAsync(object item, CancellationToken cance
     }
     public async ValueTask PublishEventAsync(string topic, IMessage evt, CancellationToken cancellationToken = default)
     {
-        await PublishEventAsync(evt.ToCloudEvent(topic), cancellationToken).ConfigureAwait(false);
+        await PublishEventAsync(evt.ToCloudEvent(key: GetType().Name, topic: topic), cancellationToken).ConfigureAwait(false);
     }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index a4bbe9aa5656..700dc20b0885 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -2,44 +2,68 @@
 // AgentWorker.cs
 
 using System.Collections.Concurrent;
+using System.Diagnostics;
 using System.Threading.Channels;
 using Microsoft.AutoGen.Contracts;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
 
 namespace Microsoft.AutoGen.Core;
 
-public class AgentWorker(
-IHostApplicationLifetime hostApplicationLifetime,
-IServiceProvider serviceProvider,
-[FromKeyedServices("AgentTypes")] IEnumerable<Tuple<string, Type>> configuredAgentTypes) :
-     IHostedService,
-     IAgentWorker
+/// <summary>
+/// Represents a worker that manages agents and handles messages.
+/// </summary>
+public class AgentWorker : IHostedService, IAgentWorker
 {
     private readonly ConcurrentDictionary<string, Type> _agentTypes = new();
     private readonly ConcurrentDictionary<(string Type, string Key), Agent> _agents = new();
+    private readonly ILogger<AgentWorker> _logger;
     private readonly Channel<object> _mailbox = Channel.CreateUnbounded<object>();
     private readonly ConcurrentDictionary<string, AgentState> _agentStates = new();
     private readonly ConcurrentDictionary<string, (Agent Agent, string OriginalRequestId)> _pendingClientRequests = new();
-    private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping);
-    public IServiceProvider ServiceProvider { get; } = serviceProvider;
-    private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes = configuredAgentTypes;
-    private readonly ConcurrentDictionary<string, Subscription> _subscriptionsByAgentType = new();
-    private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
+    private readonly CancellationTokenSource _shutdownCts;
+    public IServiceProvider ServiceProvider { get; }
+    private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes;
+    private readonly DistributedContextPropagator _distributedContextPropagator;
     private readonly CancellationTokenSource _shutdownCancellationToken = new();
     private Task? _mailboxTask;
     private readonly object _channelLock = new();
 
-    // this is the in-memory version - we just pass the message directly to the agent(s) that handle this type of event
+    /// <summary>
+    /// Initializes a new instance of the <see cref="AgentWorker"/> class.
+    /// </summary>
+    /// <param name="hostApplicationLifetime">The application lifetime.</param>
+    /// <param name="serviceProvider">The service provider.</param>
+    /// <param name="configuredAgentTypes">The configured agent types.</param>
+    /// <param name="logger">The logger.</param>
+    /// <param name="distributedContextPropagator">The distributed context propagator.</param>
+    public AgentWorker(
+        IHostApplicationLifetime hostApplicationLifetime,
+        IServiceProvider serviceProvider,
+        [FromKeyedServices("AgentTypes")] IEnumerable<Tuple<string, Type>> configuredAgentTypes,
+        ILogger<AgentWorker> logger,
+        DistributedContextPropagator distributedContextPropagator)
+    {
+        _logger = logger;
+        ServiceProvider = serviceProvider;
+        _configuredAgentTypes = configuredAgentTypes;
+        _distributedContextPropagator = distributedContextPropagator;
+        _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping);
+    }
+
+    /// <inheritdoc />
     public async ValueTask PublishEventAsync(CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
         foreach (var (typeName, _) in _agentTypes)
         {
             if (typeName == nameof(Client)) { continue; }
-            var agent = GetOrActivateAgent(new AgentId(typeName, cloudEvent.Source));
+            var agent = GetOrActivateAgent(new AgentId { Type = typeName, Key = cloudEvent.GetSubject() });
             agent.ReceiveMessage(new Message { CloudEvent = cloudEvent });
         }
     }
+
+    /// <inheritdoc />
     public async ValueTask SendRequestAsync(Agent agent, RpcRequest request, CancellationToken cancellationToken = default)
     {
         var requestId = Guid.NewGuid().ToString();
@@ -47,21 +71,28 @@ public async ValueTask SendRequestAsync(Agent agent, RpcRequest request, Cancell
         request.RequestId = requestId;
         await _mailbox.Writer.WriteAsync(request, cancellationToken).ConfigureAwait(false);
     }
+
+    /// <inheritdoc />
     public ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default)
     {
         return _mailbox.Writer.WriteAsync(new Message { Response = response }, cancellationToken);
     }
+
+    /// <inheritdoc />
     public ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default)
     {
         return _mailbox.Writer.WriteAsync(message, cancellationToken);
     }
+
+    /// <inheritdoc />
     public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default)
     {
         var agentId = value.AgentId ?? throw new InvalidOperationException("AgentId is required when saving AgentState.");
-        // add or update _agentStates with the new state
         var response = _agentStates.AddOrUpdate(agentId.ToString(), value, (key, oldValue) => value);
         return ValueTask.CompletedTask;
     }
+
+    /// <inheritdoc />
     public ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default)
     {
         _agentStates.TryGetValue(agentId.ToString(), out var state);
@@ -74,6 +105,10 @@ public ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancel
             throw new KeyNotFoundException($"Failed to read AgentState for {agentId}.");
         }
     }
+
+    /// <summary>
+    /// Runs the message pump.
+    /// </summary>
     public async Task RunMessagePump()
     {
         await Task.CompletedTask.ConfigureAwait(ConfigureAwaitOptions.ForceYielding);
@@ -162,6 +197,8 @@ void StartCore()
             }
         }
     }
+
+    /// <inheritdoc />
     public async Task StopAsync(CancellationToken cancellationToken)
     {
         _shutdownCts.Cancel();
@@ -176,16 +213,26 @@ public async Task StopAsync(CancellationToken cancellationToken)
         {
         }
     }
+
+    /// <summary>
+    /// Gets or activates an agent.
+    /// </summary>
+    /// <param name="agentId">The agent ID.</param>
+    /// <returns>The activated agent.</returns>
+
     private 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);
-
+                using (var scope = ServiceProvider.CreateScope())
+                {
+                    var scopedProvider = scope.ServiceProvider;
+                    agent = (Agent)ActivatorUtilities.CreateInstance(scopedProvider, agentType);
+                    Agent.Initialize(this, agent);
+                    _agents.TryAdd((agentId.Type, agentId.Key), agent);
+                }
             }
             else
             {
@@ -195,4 +242,9 @@ private Agent GetOrActivateAgent(AgentId agentId)
 
         return agent;
     }
+
+    public ValueTask<List<string>> GetSubscriptionsAsync(Type type)
+    {
+        throw new NotImplementedException();
+    }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
index 13e18cf6f8d0..ad22df9cd08a 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
@@ -12,4 +12,5 @@ public interface IAgentWorker
     ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default);
     ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default);
     ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
+    ValueTask<List<string>> GetSubscriptionsAsync(Type type);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
new file mode 100644
index 000000000000..5ac9d43cf092
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
@@ -0,0 +1,96 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// MessageExtensions.cs
+
+using Google.Protobuf;
+using Google.Protobuf.WellKnownTypes;
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Core;
+
+/// <summary>
+/// Provides extension methods for converting messages to and from various formats.
+/// </summary>
+public static class MessageExtensions
+{
+    private const string PROTO_DATA_CONTENT_TYPE = "application/x-protobuf";
+
+    /// <summary>
+    /// Converts a message to a CloudEvent.
+    /// </summary>
+    /// <typeparam name="T">The type of the message.</typeparam>
+    /// <param name="message">The message to convert.</param>
+    /// <param name="key">The key of the event, maps to the Topic Type</param>
+    /// <param name="topic">The topic of the event, </param>
+    /// <returns>A CloudEvent representing the message.</returns>
+    public static CloudEvent ToCloudEvent<T>(this T message, string key, string topic) where T : IMessage
+    {
+        return new CloudEvent
+        {
+            ProtoData = Any.Pack(message),
+            Type = message.Descriptor.FullName,
+            Source = topic,
+            Id = Guid.NewGuid().ToString(),
+            Attributes = {
+                {
+                    "datacontenttype", new CloudEvent.Types.CloudEventAttributeValue { CeString = PROTO_DATA_CONTENT_TYPE }
+                },
+                {
+                    "subject", new CloudEvent.Types.CloudEventAttributeValue { CeString = key }
+                }
+            }
+        };
+    }
+
+    /// <summary>
+    /// Converts a CloudEvent back to a message.
+    /// </summary>
+    /// <typeparam name="T">The type of the message.</typeparam>
+    /// <param name="cloudEvent">The CloudEvent to convert.</param>
+    /// <returns>The message represented by the CloudEvent.</returns>
+    public static T FromCloudEvent<T>(this CloudEvent cloudEvent) where T : IMessage, new()
+    {
+        return cloudEvent.ProtoData.Unpack<T>();
+    }
+
+    /// <summary>
+    public static string GetSubject(this CloudEvent cloudEvent)
+    {
+        return cloudEvent.Attributes["subject"].CeString;
+    }
+
+    /// <summary>
+    /// Converts a state to an AgentState.
+    /// </summary>
+    /// <typeparam name="T">The type of the state.</typeparam>
+    /// <param name="state">The state to convert.</param>
+    /// <param name="agentId">The ID of the agent.</param>
+    /// <param name="eTag">The ETag of the state.</param>
+    /// <returns>An AgentState representing the state.</returns>
+    public static AgentState ToAgentState<T>(this T state, AgentId agentId, string eTag) where T : IMessage
+    {
+        return new AgentState
+        {
+            ProtoData = Any.Pack(state),
+            AgentId = agentId,
+            ETag = eTag
+        };
+    }
+
+    /// <summary>
+    /// Converts an AgentState back to a state.
+    /// </summary>
+    /// <typeparam name="T">The type of the state.</typeparam>
+    /// <param name="state">The AgentState to convert.</param>
+    /// <returns>The state represented by the AgentState.</returns>
+    public static T FromAgentState<T>(this AgentState state) where T : IMessage, new()
+    {
+        if (state.HasTextData == true)
+        {
+            if (typeof(T) == typeof(AgentState))
+            {
+                return (T)(IMessage)state;
+            }
+        }
+        return state.ProtoData.Unpack<T>();
+    }
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
index e89236314842..7719a294fa48 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -14,6 +14,7 @@ public class UninitializedAgentWorker() : IAgentWorker
     public ValueTask SendRequestAsync(Agent agent, RpcRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<List<string>> GetSubscriptionsAsync(Type type) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public class AgentInitalizedIncorrectlyException(string message) : Exception(message)
     {
     }
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
index fc8260f51d8b..1b3c10350a6c 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
@@ -19,7 +19,7 @@ public async Task Handle(NewMessageReceived item, CancellationToken cancellation
     {
         ReceivedMessages[AgentId.Key] = item.Message;
         var hello = new Hello { Message = item.Message };
-        await PublishEventAsync(hello);
+        await PublishMessageAsync(hello);
     }
     public Task Handle(GoodBye item, CancellationToken cancellationToken)
     {
@@ -39,7 +39,7 @@ public async Task Handle(Hello item, CancellationToken cancellationToken)
     {
         _logger.LogInformation($"Received Hello message {item.Message}");
         ReceivedMessages[AgentId.Key] = item.Message;
-        await PublishEventAsync(new GoodBye { Message = "" });
+        await PublishMessageAsync(new GoodBye { Message = "" });
     }
 
     public static ConcurrentDictionary<string, object> ReceivedMessages { get; private set; } = new();

From e42123c234079a50558210e6e77aa63b600560e4 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sat, 21 Dec 2024 21:05:03 -0800
Subject: [PATCH 015/110] getting it all to build

---
 README.md                                     |   6 +-
 dotnet/AutoGen.sln                            |  28 +---
 .../Hello/HelloAIAgents/HelloAIAgent.cs       |   6 +-
 dotnet/samples/Hello/HelloAIAgents/Program.cs |   8 +-
 dotnet/samples/Hello/HelloAgent/Program.cs    |   2 +-
 dotnet/samples/Hello/HelloAgent/README.md     |   8 +-
 .../samples/Hello/HelloAgentState/Program.cs  |  10 +-
 .../samples/Hello/HelloAgentState/README.md   |   8 +-
 .../DevTeam.AgentHost.csproj                  |  17 ---
 .../dev-team/DevTeam.AgentHost/Program.cs     |  15 ---
 .../Properties/launchSettings.json            |  12 --
 .../appsettings.Development.json              |   8 --
 .../DevTeam.Agents/DevTeam.Agents.csproj      |  18 ---
 .../DevTeam.Agents/Developer/Developer.cs     |  63 ---------
 .../DeveloperLead/DeveloperLead.cs            |  70 ----------
 .../ProductManager/ProductManager.cs          |  63 ---------
 .../dev-team/DevTeam.Agents/Program.cs        |  23 ----
 .../Properties/launchSettings.json            |  12 --
 .../appsettings.Development.json              |   8 --
 .../DevTeam.AppHost/DevTeam.AppHost.csproj    |   2 -
 .../dev-team/DevTeam.AppHost/Program.cs       |  32 ++---
 .../Properties/launchSettings.json            |  29 +++++
 .../DevTeam.Backend/Agents/AzureGenie.cs      |  18 +--
 .../Agents/Developer/Developer.cs             |  60 +++++++++
 .../Agents}/Developer/DeveloperPrompts.cs     |   2 +-
 .../Agents/DeveloperLead/DeveloperLead.cs     |  65 ++++++++++
 .../DeveloperLead/DeveloperLeadPrompts.cs     |   2 +-
 .../dev-team/DevTeam.Backend/Agents/Hubber.cs |  26 ++--
 .../Agents}/ProductManager/PMPrompts.cs       |   2 +-
 .../Agents/ProductManager/ProductManager.cs   |  59 +++++++++
 .../DevTeam.Backend/Agents/Sandbox.cs         |   2 +-
 .../dev-team/DevTeam.Backend/AiAgent.cs       |  23 ++++
 .../dev-team/DevTeam.Backend/Consts.cs        |   9 ++
 .../DevTeam.Backend/DevTeam.Backend.csproj    |  24 ++--
 .../Models/DevPlan.cs                         |   0
 .../Options/AzureOptions.cs                   |   0
 .../Options/GithubOptions.cs                  |   0
 .../dev-team/DevTeam.Backend/Program.cs       |  22 ++--
 .../DevTeam.Backend/Services/AzureService.cs  |   2 +-
 .../Services/GithubAuthService.cs             |   2 +-
 .../DevTeam.Backend/Services/GithubService.cs |   2 +-
 .../Services/GithubWebHookProcessor.cs        |  32 ++---
 .../DevTeam.ServiceDefaults.csproj            |  22 ++++
 .../DevTeam.ServiceDefaults/Extensions.cs     | 120 ++++++++++++++++++
 .../DevTeam.Shared/DevTeam.Shared.csproj      |  27 ----
 .../DevTeam.Shared/EventExtensions.cs         |  51 --------
 .../DevTeam.Shared/ParseExtensions.cs         |  18 ---
 dotnet/samples/dev-team/Protos/messages.proto |   2 +-
 dotnet/samples/dev-team/Protos/states.proto   |   2 +-
 dotnet/samples/dev-team/dev team.sln          |  49 -------
 .../Agents/AIAgent/InferenceAgent.cs          |   5 +-
 .../Agents/AIAgent/SKAiAgent.cs               |   2 -
 .../IOAgent/ConsoleAgent/ConsoleAgent.cs      |   6 +-
 .../IOAgent/ConsoleAgent/IHandleConsole.cs    |   2 +-
 .../Agents/IOAgent/FileAgent/FileAgent.cs     |   9 +-
 .../Agents/IOAgent/IOAgent.cs                 |   6 +-
 .../Agents/IOAgent/WebAPIAgent/WebAPIAgent.cs |   7 +-
 .../Core.Grpc/GrpcAgentWorker.cs              |  16 ++-
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    |  14 +-
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs |  78 +++++-------
 .../Microsoft.AutoGen/Core/IAgentWorker.cs    |   4 +-
 .../Core/UninitializedAgentWorker.cs          |   4 +-
 .../Runtime.Grpc/Abstractions/IGateway.cs     |   2 +-
 .../Runtime.Grpc/Abstractions/IRegistry.cs    |   4 +-
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs |  16 +--
 .../Services/Grpc/GrpcGatewayService.cs       |   2 +-
 .../Services/Orleans/RegistryGrain.cs         |   4 +-
 ...ate.cs => SubscriptionRequestSurrogate.cs} |  20 +--
 ...te.cs => SubscriptionResponseSurrogate.cs} |  20 +--
 .../AgentTests.cs                             |   2 +
 .../GrpcGatewayServiceTests.cs                |   1 +
 .../TestAgent.cs                              |   4 +-
 protos/agent_worker.proto                     |  11 +-
 .../runtimes/grpc/_worker_runtime.py          |  12 +-
 .../grpc/_worker_runtime_host_servicer.py     |  10 +-
 .../runtimes/grpc/protos/agent_worker_pb2.py  |  48 +++----
 .../runtimes/grpc/protos/agent_worker_pb2.pyi |  36 ++++--
 .../grpc/protos/agent_worker_pb2_grpc.py      |  99 +++++++++++++++
 .../grpc/protos/agent_worker_pb2_grpc.pyi     |  51 ++++++++
 79 files changed, 821 insertions(+), 765 deletions(-)
 delete mode 100644 dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj
 delete mode 100644 dotnet/samples/dev-team/DevTeam.AgentHost/Program.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.AgentHost/Properties/launchSettings.json
 delete mode 100644 dotnet/samples/dev-team/DevTeam.AgentHost/appsettings.Development.json
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/Developer/Developer.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLead.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/ProductManager/ProductManager.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/Program.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/Properties/launchSettings.json
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Agents/appsettings.Development.json
 create mode 100644 dotnet/samples/dev-team/DevTeam.AppHost/Properties/launchSettings.json
 create mode 100644 dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/Developer.cs
 rename dotnet/samples/dev-team/{DevTeam.Agents => DevTeam.Backend/Agents}/Developer/DeveloperPrompts.cs (98%)
 create mode 100644 dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLead.cs
 rename dotnet/samples/dev-team/{DevTeam.Agents => DevTeam.Backend/Agents}/DeveloperLead/DeveloperLeadPrompts.cs (98%)
 rename dotnet/samples/dev-team/{DevTeam.Agents => DevTeam.Backend/Agents}/ProductManager/PMPrompts.cs (97%)
 create mode 100644 dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/ProductManager.cs
 create mode 100644 dotnet/samples/dev-team/DevTeam.Backend/AiAgent.cs
 create mode 100644 dotnet/samples/dev-team/DevTeam.Backend/Consts.cs
 rename dotnet/samples/dev-team/{DevTeam.Shared => DevTeam.Backend}/Models/DevPlan.cs (100%)
 rename dotnet/samples/dev-team/{DevTeam.Shared => DevTeam.Backend}/Options/AzureOptions.cs (100%)
 rename dotnet/samples/dev-team/{DevTeam.Shared => DevTeam.Backend}/Options/GithubOptions.cs (100%)
 create mode 100644 dotnet/samples/dev-team/DevTeam.ServiceDefaults/DevTeam.ServiceDefaults.csproj
 create mode 100644 dotnet/samples/dev-team/DevTeam.ServiceDefaults/Extensions.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Shared/EventExtensions.cs
 delete mode 100644 dotnet/samples/dev-team/DevTeam.Shared/ParseExtensions.cs
 delete mode 100644 dotnet/samples/dev-team/dev team.sln
 rename dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/{AddSubscriptionRequestSurrogate.cs => SubscriptionRequestSurrogate.cs} (51%)
 rename dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/{AddSubscriptionResponseSurrogate.cs => SubscriptionResponseSurrogate.cs} (53%)

diff --git a/README.md b/README.md
index 4b5fd029e5b8..6c036f8e3889 100644
--- a/README.md
+++ b/README.md
@@ -187,14 +187,14 @@ await app.WaitForShutdownAsync();
 [TopicSubscription("agents")]
 public class HelloAgent(
     IAgentContext worker,
-    [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : ConsoleAgent(
+    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : ConsoleAgent(
         worker,
         typeRegistry),
         ISayHello,
         IHandle<NewMessageReceived>,
         IHandle<ConversationClosed>
 {
-    public async Task Handle(NewMessageReceived item)
+    public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
     {
         var response = await SayHello(item.Message).ConfigureAwait(false);
         var evt = new Output
@@ -209,7 +209,7 @@ public class HelloAgent(
         }.ToCloudEvent(this.AgentId.Key);
         await PublishEventAsync(goodbye).ConfigureAwait(false);
     }
-    public async Task Handle(ConversationClosed item)
+    public async Task Handle(ConversationClosed item, CancellationToken cancellationToken = default)
     {
         var goodbye = $"*********************  {item.UserId} said {item.UserMessage}  ************************";
         var evt = new Output
diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index 474371b3b85f..116411d25489 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -100,16 +100,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutoGen.WebAPI.Sample", "sa
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DevTeam", "DevTeam", "{05B9C173-6441-4DCA-9AC4-E897EF75F331}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.AgentHost", "samples\dev-team\DevTeam.AgentHost\DevTeam.AgentHost.csproj", "{462A357B-7BB9-4927-A9FD-4FB7675898E9}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Agents", "samples\dev-team\DevTeam.Agents\DevTeam.Agents.csproj", "{83BBB833-A2F0-4A4D-BA1B-8229FC9BCD4F}"
-EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.AppHost", "samples\dev-team\DevTeam.AppHost\DevTeam.AppHost.csproj", "{63280C12-3BE3-4C4E-805E-584CDC6BC1F5}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Backend", "samples\dev-team\DevTeam.Backend\DevTeam.Backend.csproj", "{EDA3EF83-FC7F-4BCF-945D-B893620EE4B1}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Shared", "samples\dev-team\DevTeam.Shared\DevTeam.Shared.csproj", "{01F5D7C3-41EB-409C-9B77-A945C07FA7E8}"
-EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hello", "Hello", "{7EB336C2-7C0A-4BC8-80C6-A3173AB8DC45}"
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hello.AppHost", "samples\Hello\Hello.AppHost\Hello.AppHost.csproj", "{09A373A0-8169-409F-8C37-3FBC1654B122}"
@@ -146,6 +140,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Tests.Sha
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Tests", "test\Microsoft.AutoGen.Core.Tests\Microsoft.AutoGen.Core.Tests.csproj", "{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.ServiceDefaults", "samples\dev-team\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj", "{599E1971-1DA9-453F-A7A8-42510BBC95C2}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -300,14 +296,6 @@ Global
 		{4385AFCF-AB4A-49B2-BEBA-D33C950E1EE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{4385AFCF-AB4A-49B2-BEBA-D33C950E1EE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{4385AFCF-AB4A-49B2-BEBA-D33C950E1EE6}.Release|Any CPU.Build.0 = Release|Any CPU
-		{462A357B-7BB9-4927-A9FD-4FB7675898E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{462A357B-7BB9-4927-A9FD-4FB7675898E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{462A357B-7BB9-4927-A9FD-4FB7675898E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{462A357B-7BB9-4927-A9FD-4FB7675898E9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{83BBB833-A2F0-4A4D-BA1B-8229FC9BCD4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{83BBB833-A2F0-4A4D-BA1B-8229FC9BCD4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{83BBB833-A2F0-4A4D-BA1B-8229FC9BCD4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{83BBB833-A2F0-4A4D-BA1B-8229FC9BCD4F}.Release|Any CPU.Build.0 = Release|Any CPU
 		{63280C12-3BE3-4C4E-805E-584CDC6BC1F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{63280C12-3BE3-4C4E-805E-584CDC6BC1F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{63280C12-3BE3-4C4E-805E-584CDC6BC1F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -316,10 +304,6 @@ Global
 		{EDA3EF83-FC7F-4BCF-945D-B893620EE4B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{EDA3EF83-FC7F-4BCF-945D-B893620EE4B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{EDA3EF83-FC7F-4BCF-945D-B893620EE4B1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{01F5D7C3-41EB-409C-9B77-A945C07FA7E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{01F5D7C3-41EB-409C-9B77-A945C07FA7E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{01F5D7C3-41EB-409C-9B77-A945C07FA7E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{01F5D7C3-41EB-409C-9B77-A945C07FA7E8}.Release|Any CPU.Build.0 = Release|Any CPU
 		{09A373A0-8169-409F-8C37-3FBC1654B122}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{09A373A0-8169-409F-8C37-3FBC1654B122}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{09A373A0-8169-409F-8C37-3FBC1654B122}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -384,6 +368,10 @@ Global
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -429,11 +417,8 @@ Global
 		{CB8824F5-9475-451F-87E8-F2AEF2490A12} = {668726B9-77BC-45CF-B576-0F0773BF1615}
 		{4385AFCF-AB4A-49B2-BEBA-D33C950E1EE6} = {668726B9-77BC-45CF-B576-0F0773BF1615}
 		{05B9C173-6441-4DCA-9AC4-E897EF75F331} = {686480D7-8FEC-4ED3-9C5D-CEBE1057A7ED}
-		{462A357B-7BB9-4927-A9FD-4FB7675898E9} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
-		{83BBB833-A2F0-4A4D-BA1B-8229FC9BCD4F} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
 		{63280C12-3BE3-4C4E-805E-584CDC6BC1F5} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
 		{EDA3EF83-FC7F-4BCF-945D-B893620EE4B1} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
-		{01F5D7C3-41EB-409C-9B77-A945C07FA7E8} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
 		{7EB336C2-7C0A-4BC8-80C6-A3173AB8DC45} = {686480D7-8FEC-4ED3-9C5D-CEBE1057A7ED}
 		{09A373A0-8169-409F-8C37-3FBC1654B122} = {7EB336C2-7C0A-4BC8-80C6-A3173AB8DC45}
 		{A20B9894-F352-4338-872A-F215A241D43D} = {7EB336C2-7C0A-4BC8-80C6-A3173AB8DC45}
@@ -451,6 +436,7 @@ Global
 		{0E7983BB-2602-421E-8B37-332E52870A10} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{14F90F79-580E-454D-BA7A-ED6D9723020D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+		{599E1971-1DA9-453F-A7A8-42510BBC95C2} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}
diff --git a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgent.cs b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgent.cs
index 0e195ca5b1dd..ba71b31a2017 100644
--- a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgent.cs
+++ b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgent.cs
@@ -8,17 +8,15 @@
 namespace Hello;
 [TopicSubscription("agents")]
 public class HelloAIAgent(
-    IAgentWorker worker,
-    [FromKeyedServices("EventTypes")] EventTypes typeRegistry,
+    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry,
     IHostApplicationLifetime hostApplicationLifetime,
     IChatClient client) : HelloAgent(
-        worker,
         typeRegistry,
         hostApplicationLifetime),
         IHandle<NewMessageReceived>
 {
     // This Handle supercedes the one in the base class
-    public new async Task Handle(NewMessageReceived item)
+    public new async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
     {
         var prompt = "Please write a limerick greeting someone with the name " + item.Message;
         var response = await client.CompleteAsync(prompt);
diff --git a/dotnet/samples/Hello/HelloAIAgents/Program.cs b/dotnet/samples/Hello/HelloAIAgents/Program.cs
index f9780d62af98..a5bf4b68ee46 100644
--- a/dotnet/samples/Hello/HelloAIAgents/Program.cs
+++ b/dotnet/samples/Hello/HelloAIAgents/Program.cs
@@ -33,16 +33,14 @@ namespace Hello
 {
     [TopicSubscription("agents")]
     public class HelloAgent(
-        IAgentWorker worker,
-        [FromKeyedServices("EventTypes")] EventTypes typeRegistry,
+        [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry,
         IHostApplicationLifetime hostApplicationLifetime) : ConsoleAgent(
-            worker,
             typeRegistry),
             ISayHello,
             IHandle<NewMessageReceived>,
             IHandle<ConversationClosed>
     {
-        public async Task Handle(NewMessageReceived item)
+        public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
         {
             var response = await SayHello(item.Message).ConfigureAwait(false);
             var evt = new Output
@@ -57,7 +55,7 @@ public async Task Handle(NewMessageReceived item)
             };
             await PublishMessageAsync(goodbye).ConfigureAwait(false);
         }
-        public async Task Handle(ConversationClosed item)
+        public async Task Handle(ConversationClosed item, CancellationToken cancellationToken = default)
         {
             var goodbye = $"*********************  {item.UserId} said {item.UserMessage}  ************************";
             var evt = new Output
diff --git a/dotnet/samples/Hello/HelloAgent/Program.cs b/dotnet/samples/Hello/HelloAgent/Program.cs
index 9c3a038260b7..980c34f8617c 100644
--- a/dotnet/samples/Hello/HelloAgent/Program.cs
+++ b/dotnet/samples/Hello/HelloAgent/Program.cs
@@ -19,7 +19,7 @@ namespace Hello
     [TopicSubscription("agents")]
     public class HelloAgent(
         IHostApplicationLifetime hostApplicationLifetime,
-        [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : Agent(
+        [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : Agent(
             typeRegistry),
             ISayHello,
             IHandleConsole,
diff --git a/dotnet/samples/Hello/HelloAgent/README.md b/dotnet/samples/Hello/HelloAgent/README.md
index 067f04f3c30a..968f454905c3 100644
--- a/dotnet/samples/Hello/HelloAgent/README.md
+++ b/dotnet/samples/Hello/HelloAgent/README.md
@@ -25,10 +25,10 @@ Flow Diagram:
 ```mermaid
 %%{init: {'theme':'forest'}}%%
 graph LR;
-    A[Main] --> |"PublishEventAsync(NewMessage('World'))"| B{"Handle(NewMessageReceived item)"}
+    A[Main] --> |"PublishEventAsync(NewMessage('World'))"| B{"Handle(NewMessageReceived item, CancellationToken cancellationToken = default)"}
     B --> |"PublishEventAsync(Output('***Hello, World***'))"| C[ConsoleAgent]
     C --> D{"WriteConsole()"}
-    B --> |"PublishEventAsync(ConversationClosed('Goodbye'))"| E{"Handle(ConversationClosed item)"}
+    B --> |"PublishEventAsync(ConversationClosed('Goodbye'))"| E{"Handle(ConversationClosed item, CancellationToken cancellationToken = default)"}
     B --> |"PublishEventAsync(Output('***Goodbye***'))"| C
     E --> F{"Shutdown()"}
 
@@ -44,14 +44,14 @@ Within that event handler you may optionally *emit* new events, which are then s
 TopicSubscription("HelloAgents")]
 public class HelloAgent(
     iAgentWorker worker,
-    [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : ConsoleAgent(
+    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : ConsoleAgent(
         worker,
         typeRegistry),
         ISayHello,
         IHandle<NewMessageReceived>,
         IHandle<ConversationClosed>
 {
-    public async Task Handle(NewMessageReceived item)
+    public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
     {
         var response = await SayHello(item.Message).ConfigureAwait(false);
         var evt = new Output
diff --git a/dotnet/samples/Hello/HelloAgentState/Program.cs b/dotnet/samples/Hello/HelloAgentState/Program.cs
index d882f1f42c4a..013d70786551 100644
--- a/dotnet/samples/Hello/HelloAgentState/Program.cs
+++ b/dotnet/samples/Hello/HelloAgentState/Program.cs
@@ -18,10 +18,8 @@ namespace Hello
 {
     [TopicSubscription("agents")]
     public class HelloAgent(
-        IAgentWorker worker,
         IHostApplicationLifetime hostApplicationLifetime,
-        [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : Agent(
-            worker,
+        [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : Agent(
             typeRegistry),
             IHandleConsole,
             IHandle<NewMessageReceived>,
@@ -29,7 +27,7 @@ public class HelloAgent(
             IHandle<Shutdown>
     {
         private AgentState? State { get; set; }
-        public async Task Handle(NewMessageReceived item)
+        public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
         {
             var response = await SayHello(item.Message).ConfigureAwait(false);
             var evt = new Output
@@ -57,7 +55,7 @@ await StoreAsync(new AgentState
             await PublishMessageAsync(new Shutdown { Message = this.AgentId.Key }).ConfigureAwait(false);
 
         }
-        public async Task Handle(ConversationClosed item)
+        public async Task Handle(ConversationClosed item, CancellationToken cancellationToken = default)
         {
             State = await ReadAsync<AgentState>(this.AgentId).ConfigureAwait(false);
             var state = JsonSerializer.Deserialize<Dictionary<string, string>>(State.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
@@ -74,7 +72,7 @@ await StoreAsync(new AgentState
                 TextData = JsonSerializer.Serialize(state)
             }).ConfigureAwait(false);
         }
-        public async Task Handle(Shutdown item)
+        public async Task Handle(Shutdown item, CancellationToken cancellationToken = default)
         {
             string? workflow = null;
             // make sure the workflow is finished
diff --git a/dotnet/samples/Hello/HelloAgentState/README.md b/dotnet/samples/Hello/HelloAgentState/README.md
index c8fead8b23b1..801d79a7c8f0 100644
--- a/dotnet/samples/Hello/HelloAgentState/README.md
+++ b/dotnet/samples/Hello/HelloAgentState/README.md
@@ -25,10 +25,10 @@ Flow Diagram:
 ```mermaid
 %%{init: {'theme':'forest'}}%%
 graph LR;
-    A[Main] --> |"PublishEventAsync(NewMessage('World'))"| B{"Handle(NewMessageReceived item)"}
+    A[Main] --> |"PublishEventAsync(NewMessage('World'))"| B{"Handle(NewMessageReceived item, CancellationToken cancellationToken = default)"}
     B --> |"PublishEventAsync(Output('***Hello, World***'))"| C[ConsoleAgent]
     C --> D{"WriteConsole()"}
-    B --> |"PublishEventAsync(ConversationClosed('Goodbye'))"| E{"Handle(ConversationClosed item)"}
+    B --> |"PublishEventAsync(ConversationClosed('Goodbye'))"| E{"Handle(ConversationClosed item, CancellationToken cancellationToken = default)"}
     B --> |"PublishEventAsync(Output('***Goodbye***'))"| C
     E --> F{"Shutdown()"}
 
@@ -44,14 +44,14 @@ Within that event handler you may optionally *emit* new events, which are then s
 TopicSubscription("HelloAgents")]
 public class HelloAgent(
     iAgentWorker worker,
-    [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : ConsoleAgent(
+    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : ConsoleAgent(
         worker,
         typeRegistry),
         ISayHello,
         IHandle<NewMessageReceived>,
         IHandle<ConversationClosed>
 {
-    public async Task Handle(NewMessageReceived item)
+    public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
     {
         var response = await SayHello(item.Message).ConfigureAwait(false);
         var evt = new Output
diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj
deleted file mode 100644
index 4da4bfd8d7e6..000000000000
--- a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj
+++ /dev/null
@@ -1,17 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
-  <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-    <Nullable>enable</Nullable>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <!--orleans doesn't have strong name package-->
-    <NoWarn>$(NoWarn);CS8002</NoWarn> 
-  </PropertyGroup>
-
-   <ItemGroup>
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core/Microsoft.AutoGen.Core.csproj" />
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Runtime.Grpc/Microsoft.AutoGen.Runtime.Grpc.csproj" />
-    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Extensions\Aspire\Microsoft.AutoGen.Extensions.Aspire.csproj" />
-  </ItemGroup>
-
-</Project>
diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/Program.cs b/dotnet/samples/dev-team/DevTeam.AgentHost/Program.cs
deleted file mode 100644
index 82a2bf22ce98..000000000000
--- a/dotnet/samples/dev-team/DevTeam.AgentHost/Program.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Program.cs
-using Microsoft.AutoGen.Runtime.Grpc;
-
-var builder = WebApplication.CreateBuilder(args);
-
-builder.AddServiceDefaults();
-builder.AddAgentService();
-
-var app = builder.Build();
-
-app.MapDefaultEndpoints();
-app.MapAgentService();
-
-app.Run();
diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/Properties/launchSettings.json b/dotnet/samples/dev-team/DevTeam.AgentHost/Properties/launchSettings.json
deleted file mode 100644
index c43e7586ac17..000000000000
--- a/dotnet/samples/dev-team/DevTeam.AgentHost/Properties/launchSettings.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "profiles": {
-    "DevTeam.AgentHost": {
-      "commandName": "Project",
-      "launchBrowser": true,
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      },
-      "applicationUrl": "https://localhost:50670;http://localhost:50673"
-    }
-  }
-}
\ No newline at end of file
diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/appsettings.Development.json b/dotnet/samples/dev-team/DevTeam.AgentHost/appsettings.Development.json
deleted file mode 100644
index 0c208ae9181e..000000000000
--- a/dotnet/samples/dev-team/DevTeam.AgentHost/appsettings.Development.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft.AspNetCore": "Warning"
-    }
-  }
-}
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj
deleted file mode 100644
index bc70545810bc..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj
+++ /dev/null
@@ -1,18 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
-  <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-    <Nullable>enable</Nullable>
-    <ImplicitUsings>enable</ImplicitUsings>
-  </PropertyGroup>
-
-  <ItemGroup>
-
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core/Microsoft.AutoGen.Core.csproj" />
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj" />   
-    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Extensions\Aspire\Microsoft.AutoGen.Extensions.Aspire.csproj" />
-    <ProjectReference Include="..\DevTeam.Shared\DevTeam.Shared.csproj" />
-    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Extensions\SemanticKernel\Microsoft.AutoGen.Extensions.SemanticKernel.csproj" />
-  </ItemGroup>
-
-</Project>
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/Developer/Developer.cs b/dotnet/samples/dev-team/DevTeam.Agents/Developer/Developer.cs
deleted file mode 100644
index ffc474a93124..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/Developer/Developer.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Developer.cs
-
-using DevTeam.Shared;
-using Microsoft.AutoGen.Agents;
-using Microsoft.AutoGen.Contracts;
-using Microsoft.AutoGen.Core;
-using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Memory;
-
-namespace DevTeam.Agents;
-
-[TopicSubscription("devteam")]
-public class Dev(IAgentWorker worker, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, ILogger<Dev> logger)
-    : SKAiAgent<DeveloperState>(worker, memory, kernel, typeRegistry), IDevelopApps,
-    IHandle<CodeGenerationRequested>,
-    IHandle<CodeChainClosed>
-{
-    public async Task Handle(CodeGenerationRequested item)
-    {
-        var code = await GenerateCode(item.Ask);
-        var evt = new CodeGenerated
-        {
-            Org = item.Org,
-            Repo = item.Repo,
-            IssueNumber = item.IssueNumber,
-            Code = code
-        };
-        await PublishMessageAsync(evt);
-    }
-
-    public async Task Handle(CodeChainClosed item)
-    {
-        //TODO: Get code from state
-        var lastCode = ""; // _state.State.History.Last().Message
-        var evt = new CodeCreated
-        {
-            Code = lastCode
-        };
-        await PublishMessageAsync(evt);
-    }
-
-    public async Task<string> GenerateCode(string ask)
-    {
-        try
-        {
-            var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
-            var instruction = "Consider the following architectural guidelines:!waf!";
-            var enhancedContext = await AddKnowledge(instruction, "waf", context);
-            return await CallFunction(DeveloperSkills.Implement, enhancedContext);
-        }
-        catch (Exception ex)
-        {
-            logger.LogError(ex, "Error generating code");
-            return "";
-        }
-    }
-}
-
-public interface IDevelopApps
-{
-    public Task<string> GenerateCode(string ask);
-}
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLead.cs b/dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLead.cs
deleted file mode 100644
index ffeefe7d430f..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLead.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// DeveloperLead.cs
-
-using DevTeam.Shared;
-using Microsoft.AutoGen.Agents;
-using Microsoft.AutoGen.Contracts;
-using Microsoft.AutoGen.Core;
-using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Connectors.OpenAI;
-using Microsoft.SemanticKernel.Memory;
-
-namespace DevTeam.Agents;
-
-[TopicSubscription("devteam")]
-public class DeveloperLead(IAgentWorker worker, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, ILogger<DeveloperLead> logger)
-    : SKAiAgent<DeveloperLeadState>(worker, memory, kernel, typeRegistry), ILeadDevelopers,
-    IHandle<DevPlanRequested>,
-    IHandle<DevPlanChainClosed>
-{
-    public async Task Handle(DevPlanRequested item)
-    {
-        var plan = await CreatePlan(item.Ask);
-        var evt = new DevPlanGenerated
-        {
-            Org = item.Org,
-            Repo = item.Repo,
-            IssueNumber = item.IssueNumber,
-            Plan = plan
-        };
-        await PublishMessageAsync(evt);
-    }
-
-    public async Task Handle(DevPlanChainClosed item)
-    {
-        // TODO: Get plan from state
-        var lastPlan = ""; // _state.State.History.Last().Message
-        var evt = new DevPlanCreated
-        {
-            Plan = lastPlan
-        };
-        await PublishMessageAsync(evt);
-    }
-    public async Task<string> CreatePlan(string ask)
-    {
-        try
-        {
-            var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
-            var instruction = "Consider the following architectural guidelines:!waf!";
-            var enhancedContext = await AddKnowledge(instruction, "waf", context);
-            var settings = new OpenAIPromptExecutionSettings
-            {
-                ResponseFormat = "json_object",
-                MaxTokens = 4096,
-                Temperature = 0.8,
-                TopP = 1
-            };
-            return await CallFunction(DevLeadSkills.Plan, enhancedContext, settings);
-        }
-        catch (Exception ex)
-        {
-            logger.LogError(ex, "Error creating development plan");
-            return "";
-        }
-    }
-}
-
-public interface ILeadDevelopers
-{
-    public Task<string> CreatePlan(string ask);
-}
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/ProductManager/ProductManager.cs b/dotnet/samples/dev-team/DevTeam.Agents/ProductManager/ProductManager.cs
deleted file mode 100644
index 5306a91838e3..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/ProductManager/ProductManager.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// ProductManager.cs
-
-using DevTeam.Shared;
-using Microsoft.AutoGen.Agents;
-using Microsoft.AutoGen.Contracts;
-using Microsoft.AutoGen.Core;
-using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Memory;
-
-namespace DevTeam.Agents;
-
-[TopicSubscription("devteam")]
-public class ProductManager(IAgentWorker worker, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, ILogger<ProductManager> logger)
-    : SKAiAgent<ProductManagerState>(worker, memory, kernel, typeRegistry), IManageProducts,
-    IHandle<ReadmeChainClosed>,
-    IHandle<ReadmeRequested>
-{
-    public async Task Handle(ReadmeChainClosed item)
-    {
-        // TODO: Get readme from state
-        var lastReadme = ""; // _state.State.History.Last().Message
-        var evt = new ReadmeCreated
-        {
-            Readme = lastReadme
-        };
-        await PublishMessageAsync(evt);
-    }
-
-    public async Task Handle(ReadmeRequested item)
-    {
-        var readme = await CreateReadme(item.Ask);
-        var evt = new ReadmeGenerated
-        {
-            Readme = readme,
-            Org = item.Org,
-            Repo = item.Repo,
-            IssueNumber = item.IssueNumber
-        };
-        await PublishMessageAsync(evt);
-    }
-
-    public async Task<string> CreateReadme(string ask)
-    {
-        try
-        {
-            var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
-            var instruction = "Consider the following architectural guidelines:!waf!";
-            var enhancedContext = await AddKnowledge(instruction, "waf", context);
-            return await CallFunction(PMSkills.Readme, enhancedContext);
-        }
-        catch (Exception ex)
-        {
-            logger.LogError(ex, "Error creating readme");
-            return "";
-        }
-    }
-}
-
-public interface IManageProducts
-{
-    public Task<string> CreateReadme(string ask);
-}
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/Program.cs b/dotnet/samples/dev-team/DevTeam.Agents/Program.cs
deleted file mode 100644
index bd9e4ad24832..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/Program.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Program.cs
-
-using DevTeam.Agents;
-using Microsoft.AutoGen.Core;
-using Microsoft.AutoGen.Extensions.SemanticKernel;
-
-var builder = WebApplication.CreateBuilder(args);
-
-builder.AddServiceDefaults();
-
-builder.ConfigureSemanticKernel();
-
-builder.AddAgentWorker(builder.Configuration["AGENT_HOST"]!)
-    .AddAgent<Dev>(nameof(Dev))
-    .AddAgent<ProductManager>(nameof(ProductManager))
-    .AddAgent<DeveloperLead>(nameof(DeveloperLead));
-
-var app = builder.Build();
-
-app.MapDefaultEndpoints();
-
-app.Run();
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/Properties/launchSettings.json b/dotnet/samples/dev-team/DevTeam.Agents/Properties/launchSettings.json
deleted file mode 100644
index 8edfece6ad8d..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/Properties/launchSettings.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
-  "profiles": {
-    "DevTeam.Agents": {
-      "commandName": "Project",
-      "launchBrowser": true,
-      "environmentVariables": {
-        "ASPNETCORE_ENVIRONMENT": "Development"
-      },
-      "applicationUrl": "https://localhost:50669;http://localhost:50671"
-    }
-  }
-}
\ No newline at end of file
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/appsettings.Development.json b/dotnet/samples/dev-team/DevTeam.Agents/appsettings.Development.json
deleted file mode 100644
index 0c208ae9181e..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Agents/appsettings.Development.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-  "Logging": {
-    "LogLevel": {
-      "Default": "Information",
-      "Microsoft.AspNetCore": "Warning"
-    }
-  }
-}
diff --git a/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj b/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj
index 89d121b303ea..eab38e3ba71a 100644
--- a/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj
+++ b/dotnet/samples/dev-team/DevTeam.AppHost/DevTeam.AppHost.csproj
@@ -21,8 +21,6 @@
 
    <ItemGroup>
     <ProjectReference Include="..\DevTeam.Backend\DevTeam.Backend.csproj" />
-    <ProjectReference Include="..\DevTeam.AgentHost\DevTeam.AgentHost.csproj" />
-    <ProjectReference Include="..\DevTeam.Agents\DevTeam.Agents.csproj" />
   </ItemGroup>
 
 </Project>
diff --git a/dotnet/samples/dev-team/DevTeam.AppHost/Program.cs b/dotnet/samples/dev-team/DevTeam.AppHost/Program.cs
index 99dd61a790bc..227a35e6bcb5 100644
--- a/dotnet/samples/dev-team/DevTeam.AppHost/Program.cs
+++ b/dotnet/samples/dev-team/DevTeam.AppHost/Program.cs
@@ -7,22 +7,16 @@
 
 var qdrant = builder.AddQdrant("qdrant");
 
-var orleans = builder.AddOrleans("orleans")
-    .WithDevelopmentClustering();
+var agentHost = builder.AddContainer("agent-host", "autogen-host")
+                       .WithEnvironment("ASPNETCORE_URLS", "https://+;http://+")
+                       .WithEnvironment("ASPNETCORE_HTTPS_PORTS", "5001")
+                       .WithEnvironment("ASPNETCORE_Kestrel__Certificates__Default__Password", "mysecurepass")
+                       .WithEnvironment("ASPNETCORE_Kestrel__Certificates__Default__Path", "/https/devcert.pfx")
+                       .WithBindMount("./certs", "/https/", true)
+                       .WithHttpsEndpoint(targetPort: 5001);
 
-var agentHost = builder.AddProject<Projects.DevTeam_AgentHost>("agenthost")
-    .WithReference(orleans);
 var agentHostHttps = agentHost.GetEndpoint("https");
 
-//TODO: pass the right variables - aca environment
-// var environmentId = builder.AddParameter("environmentId");
-// var acaSessions = builder.AddBicepTemplateString(
-//         name: "aca-sessions",
-//         bicepContent: BicepTemplates.Sessions
-//     )
-//     .WithParameter("environmentId", environmentId);
-// var acaSessionsEndpoint = acaSessions.GetOutput("endpoint");
-
 builder.AddProject<Projects.DevTeam_Backend>("backend")
     .WithEnvironment("AGENT_HOST", $"{agentHostHttps.Property(EndpointProperty.Url)}")
     .WithEnvironment("Qdrant__Endpoint", $"{qdrant.Resource.HttpEndpoint.Property(EndpointProperty.Url)}")
@@ -33,16 +27,10 @@
     .WithEnvironment("Github__AppId", builder.Configuration["Github:AppId"])
     .WithEnvironment("Github__InstallationId", builder.Configuration["Github:InstallationId"])
     .WithEnvironment("Github__WebhookSecret", builder.Configuration["Github:WebhookSecret"])
-    .WithEnvironment("Github__AppKey", builder.Configuration["Github:AppKey"]);
+    .WithEnvironment("Github__AppKey", builder.Configuration["Github:AppKey"])
+    .WaitFor(agentHost)
+    .WaitFor(qdrant);
 //TODO: add this to the config in backend
 //.WithEnvironment("", acaSessionsEndpoint);
 
-builder.AddProject<Projects.DevTeam_Agents>("dev-agents")
-    .WithEnvironment("AGENT_HOST", $"{agentHostHttps.Property(EndpointProperty.Url)}")
-    .WithEnvironment("Qdrant__Endpoint", $"{qdrant.Resource.HttpEndpoint.Property(EndpointProperty.Url)}")
-    .WithEnvironment("Qdrant__ApiKey", $"{qdrant.Resource.ApiKeyParameter.Value}")
-    .WithEnvironment("Qdrant__VectorSize", "1536")
-    .WithEnvironment("OpenAI__Key", builder.Configuration["OpenAI:Key"])
-    .WithEnvironment("OpenAI__Endpoint", builder.Configuration["OpenAI:Endpoint"]);
-
 builder.Build().Run();
diff --git a/dotnet/samples/dev-team/DevTeam.AppHost/Properties/launchSettings.json b/dotnet/samples/dev-team/DevTeam.AppHost/Properties/launchSettings.json
new file mode 100644
index 000000000000..eae31b662c3d
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.AppHost/Properties/launchSettings.json
@@ -0,0 +1,29 @@
+{
+    "$schema": "https://json.schemastore.org/launchsettings.json",
+    "profiles": {
+      "https": {
+        "commandName": "Project",
+        "dotnetRunMessages": true,
+        "launchBrowser": true,
+        "applicationUrl": "https://localhost:17034;http://localhost:15043",
+        "environmentVariables": {
+          "ASPNETCORE_ENVIRONMENT": "Development",
+          "DOTNET_ENVIRONMENT": "Development",
+          "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21249",
+          "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22030"
+        }
+      },
+      "http": {
+        "commandName": "Project",
+        "dotnetRunMessages": true,
+        "launchBrowser": true,
+        "applicationUrl": "http://localhost:15043",
+        "environmentVariables": {
+          "ASPNETCORE_ENVIRONMENT": "Development",
+          "DOTNET_ENVIRONMENT": "Development",
+          "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19105",
+          "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20096"
+        }
+      }
+    }
+  }
\ No newline at end of file
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Agents/AzureGenie.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/AzureGenie.cs
index 85d498bcc5aa..59ac34ba45a3 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Agents/AzureGenie.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/AzureGenie.cs
@@ -1,21 +1,17 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // AzureGenie.cs
 
-using DevTeam.Backend;
-using DevTeam.Shared;
-using Microsoft.AutoGen.Agents;
+using DevTeam.Backend.Services;
 using Microsoft.AutoGen.Core;
-using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Memory;
-namespace Microsoft.AI.DevTeam;
+namespace DevTeam.Backend.Agents;
 
-public class AzureGenie(IAgentWorker worker, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, IManageAzure azureService)
-    : SKAiAgent<object>(worker, memory, kernel, typeRegistry),
+[TopicSubscription(Consts.TopicName)]
+public class AzureGenie([FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry, IManageAzure azureService)
+    : Agent(typeRegistry),
     IHandle<ReadmeCreated>,
     IHandle<CodeCreated>
-
 {
-    public async Task Handle(ReadmeCreated item)
+    public async Task Handle(ReadmeCreated item, CancellationToken cancellationToken = default)
     {
         // TODO: Not sure we need to store the files if we use ACA Sessions
         //                //var data = item.ToData();
@@ -30,7 +26,7 @@ public async Task Handle(ReadmeCreated item)
         await Task.CompletedTask;
     }
 
-    public async Task Handle(CodeCreated item)
+    public async Task Handle(CodeCreated item, CancellationToken cancellationToken = default)
     {
         // TODO: Not sure we need to store the files if we use ACA Sessions
         //                //var data = item.ToData();
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/Developer.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/Developer.cs
new file mode 100644
index 000000000000..b0f52f5bd5eb
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/Developer.cs
@@ -0,0 +1,60 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Developer.cs
+
+using DevTeam.Agents;
+using Microsoft.AutoGen.Core;
+
+namespace DevTeam.Backend.Agents.Developer;
+
+[TopicSubscription(Consts.TopicName)]
+public class Dev([FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry, ILogger<Dev> logger)
+    : AiAgent<DeveloperState>(typeRegistry, logger), IDevelopApps,
+    IHandle<CodeGenerationRequested>,
+    IHandle<CodeChainClosed>
+{
+    public async Task Handle(CodeGenerationRequested item, CancellationToken cancellationToken = default)
+    {
+        var code = await GenerateCode(item.Ask);
+        var evt = new CodeGenerated
+        {
+            Org = item.Org,
+            Repo = item.Repo,
+            IssueNumber = item.IssueNumber,
+            Code = code
+        };
+        // TODO: Read the Topic from the agent metadata
+        await PublishMessageAsync(evt, topic: Consts.TopicName).ConfigureAwait(false);
+    }
+
+    public async Task Handle(CodeChainClosed item, CancellationToken cancellationToken = default)
+    {
+        //TODO: Get code from state
+        var lastCode = ""; // _state.State.History.Last().Message
+        var evt = new CodeCreated
+        {
+            Code = lastCode
+        };
+        await PublishMessageAsync(evt, topic: Consts.TopicName).ConfigureAwait(false);
+    }
+
+    public async Task<string> GenerateCode(string ask)
+    {
+        try
+        {
+            //var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
+            //var instruction = "Consider the following architectural guidelines:!waf!";
+            //var enhancedContext = await AddKnowledge(instruction, "waf");
+            return await CallFunction(DeveloperSkills.Implement);
+        }
+        catch (Exception ex)
+        {
+            logger.LogError(ex, "Error generating code");
+            return "";
+        }
+    }
+}
+
+public interface IDevelopApps
+{
+    public Task<string> GenerateCode(string ask);
+}
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/Developer/DeveloperPrompts.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/DeveloperPrompts.cs
similarity index 98%
rename from dotnet/samples/dev-team/DevTeam.Agents/Developer/DeveloperPrompts.cs
rename to dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/DeveloperPrompts.cs
index d4b5a4f942d3..9b248807b656 100644
--- a/dotnet/samples/dev-team/DevTeam.Agents/Developer/DeveloperPrompts.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Developer/DeveloperPrompts.cs
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // DeveloperPrompts.cs
 
-namespace DevTeam.Agents;
+namespace DevTeam.Backend.Agents.Developer;
 public static class DeveloperSkills
 {
     public const string Implement = """
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLead.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLead.cs
new file mode 100644
index 000000000000..b935d31b8f71
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLead.cs
@@ -0,0 +1,65 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// DeveloperLead.cs
+
+using DevTeam.Agents;
+using Microsoft.AutoGen.Core;
+
+namespace DevTeam.Backend.Agents.DeveloperLead;
+
+[TopicSubscription(Consts.TopicName)]
+public class DeveloperLead([FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry, ILogger<DeveloperLead> logger)
+    : AiAgent<DeveloperLeadState>(typeRegistry, logger), ILeadDevelopers,
+    IHandle<DevPlanRequested>,
+    IHandle<DevPlanChainClosed>
+{
+    public async Task Handle(DevPlanRequested item, CancellationToken cancellationToken = default)
+    {
+        var plan = await CreatePlan(item.Ask);
+        var evt = new DevPlanGenerated
+        {
+            Org = item.Org,
+            Repo = item.Repo,
+            IssueNumber = item.IssueNumber,
+            Plan = plan
+        };
+        await PublishMessageAsync(evt, topic: Consts.TopicName).ConfigureAwait(false);
+    }
+
+    public async Task Handle(DevPlanChainClosed item, CancellationToken cancellationToken = default)
+    {
+        // TODO: Get plan from state
+        var lastPlan = ""; // _state.State.History.Last().Message
+        var evt = new DevPlanCreated
+        {
+            Plan = lastPlan
+        };
+        await PublishMessageAsync(evt, topic: Consts.TopicName).ConfigureAwait(false);
+    }
+    public async Task<string> CreatePlan(string ask)
+    {
+        try
+        {
+            //var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
+            //var instruction = "Consider the following architectural guidelines:!waf!";
+            //var enhancedContext = await AddKnowledge(instruction, "waf", context);
+            //var settings = new OpenAIPromptExecutionSettings
+            //{
+            //    ResponseFormat = "json_object",
+            //    MaxTokens = 4096,
+            //    Temperature = 0.8,
+            //    TopP = 1
+            //};
+            return await CallFunction(DevLeadSkills.Plan);
+        }
+        catch (Exception ex)
+        {
+            logger.LogError(ex, "Error creating development plan");
+            return "";
+        }
+    }
+}
+
+public interface ILeadDevelopers
+{
+    public Task<string> CreatePlan(string ask);
+}
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLeadPrompts.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLeadPrompts.cs
similarity index 98%
rename from dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLeadPrompts.cs
rename to dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLeadPrompts.cs
index 0aeb3b26dbb4..756052fdf4f5 100644
--- a/dotnet/samples/dev-team/DevTeam.Agents/DeveloperLead/DeveloperLeadPrompts.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/DeveloperLead/DeveloperLeadPrompts.cs
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // DeveloperLeadPrompts.cs
 
-namespace DevTeam.Agents;
+namespace DevTeam.Backend.Agents.DeveloperLead;
 public static class DevLeadSkills
 {
     public const string Plan = """
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Agents/Hubber.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Hubber.cs
index 3ba0eeb69b25..8ba4ddf923ce 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Agents/Hubber.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Hubber.cs
@@ -2,18 +2,14 @@
 // Hubber.cs
 
 using System.Text.Json;
-using DevTeam;
-using DevTeam.Backend;
-using DevTeam.Shared;
-using Microsoft.AutoGen.Agents;
+using DevTeam.Backend.Services;
 using Microsoft.AutoGen.Core;
-using Microsoft.SemanticKernel;
-using Microsoft.SemanticKernel.Memory;
 
-namespace Microsoft.AI.DevTeam;
+namespace DevTeam.Backend.Agents;
 
-public class Hubber(IAgentWorker worker, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, IManageGithub ghService)
-    : SKAiAgent<object>(worker, memory, kernel, typeRegistry),
+[TopicSubscription(Consts.TopicName)]
+public class Hubber([FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry, IManageGithub ghService)
+    : Agent(typeRegistry),
     IHandle<NewAsk>,
     IHandle<ReadmeGenerated>,
     IHandle<DevPlanGenerated>,
@@ -21,7 +17,7 @@ public class Hubber(IAgentWorker worker, Kernel kernel, ISemanticTextMemory memo
     IHandle<ReadmeStored>,
     IHandle<CodeGenerated>
 {
-    public async Task Handle(NewAsk item)
+    public async Task Handle(NewAsk item, CancellationToken cancellationToken = default)
     {
         var pmIssue = await CreateIssue(item.Org, item.Repo, item.Ask, "PM.Readme", item.IssueNumber);
         var devLeadIssue = await CreateIssue(item.Org, item.Repo, item.Ask, "DevLead.Plan", item.IssueNumber);
@@ -30,25 +26,25 @@ public async Task Handle(NewAsk item)
         await CreateBranch(item.Org, item.Repo, $"sk-{item.IssueNumber}");
     }
 
-    public async Task Handle(ReadmeGenerated item)
+    public async Task Handle(ReadmeGenerated item, CancellationToken cancellationToken = default)
     {
         var contents = string.IsNullOrEmpty(item.Readme) ? "Sorry, I got tired, can you try again please? " : item.Readme;
         await PostComment(item.Org, item.Repo, item.IssueNumber, contents);
     }
 
-    public async Task Handle(DevPlanGenerated item)
+    public async Task Handle(DevPlanGenerated item, CancellationToken cancellationToken = default)
     {
         var contents = string.IsNullOrEmpty(item.Plan) ? "Sorry, I got tired, can you try again please? " : item.Plan;
         await PostComment(item.Org, item.Repo, item.IssueNumber, contents);
     }
 
-    public async Task Handle(CodeGenerated item)
+    public async Task Handle(CodeGenerated item, CancellationToken cancellationToken = default)
     {
         var contents = string.IsNullOrEmpty(item.Code) ? "Sorry, I got tired, can you try again please? " : item.Code;
         await PostComment(item.Org, item.Repo, item.IssueNumber, contents);
     }
 
-    public async Task Handle(DevPlanCreated item)
+    public async Task Handle(DevPlanCreated item, CancellationToken cancellationToken = default)
     {
         var plan = JsonSerializer.Deserialize<DevLeadPlan>(item.Plan);
         var prompts = plan!.Steps.SelectMany(s => s.Subtasks!.Select(st => st.Prompt));
@@ -62,7 +58,7 @@ public async Task Handle(DevPlanCreated item)
         }
     }
 
-    public async Task Handle(ReadmeStored item)
+    public async Task Handle(ReadmeStored item, CancellationToken cancellationToken = default)
     {
         var branch = $"sk-{item.ParentNumber}";
         await CommitToBranch(item.Org, item.Repo, item.ParentNumber, item.IssueNumber, "output", branch);
diff --git a/dotnet/samples/dev-team/DevTeam.Agents/ProductManager/PMPrompts.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/PMPrompts.cs
similarity index 97%
rename from dotnet/samples/dev-team/DevTeam.Agents/ProductManager/PMPrompts.cs
rename to dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/PMPrompts.cs
index 08d173b1166e..b10092fb046c 100644
--- a/dotnet/samples/dev-team/DevTeam.Agents/ProductManager/PMPrompts.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/PMPrompts.cs
@@ -1,7 +1,7 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // PMPrompts.cs
 
-namespace DevTeam.Agents;
+namespace DevTeam.Backend.Agents.ProductManager;
 public static class PMSkills
 {
     public const string BootstrapProject = """
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/ProductManager.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/ProductManager.cs
new file mode 100644
index 000000000000..93da47e53cdd
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/ProductManager/ProductManager.cs
@@ -0,0 +1,59 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// ProductManager.cs
+
+using DevTeam.Agents;
+using Microsoft.AutoGen.Core;
+
+namespace DevTeam.Backend.Agents.ProductManager;
+
+[TopicSubscription(Consts.TopicName)]
+public class ProductManager([FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry, ILogger<ProductManager> logger)
+    : AiAgent<ProductManagerState>(typeRegistry, logger), IManageProducts,
+    IHandle<ReadmeChainClosed>,
+    IHandle<ReadmeRequested>
+{
+    public async Task Handle(ReadmeChainClosed item, CancellationToken cancellationToken = default)
+    {
+        // TODO: Get readme from state
+        var lastReadme = ""; // _state.State.History.Last().Message
+        var evt = new ReadmeCreated
+        {
+            Readme = lastReadme
+        };
+        await PublishMessageAsync(evt, topic: Consts.TopicName).ConfigureAwait(false);
+    }
+
+    public async Task Handle(ReadmeRequested item, CancellationToken cancellationToken = default)
+    {
+        var readme = await CreateReadme(item.Ask);
+        var evt = new ReadmeGenerated
+        {
+            Readme = readme,
+            Org = item.Org,
+            Repo = item.Repo,
+            IssueNumber = item.IssueNumber
+        };
+        await PublishMessageAsync(evt, topic: Consts.TopicName).ConfigureAwait(false);
+    }
+
+    public async Task<string> CreateReadme(string ask)
+    {
+        try
+        {
+            //var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
+            //var instruction = "Consider the following architectural guidelines:!waf!";
+            //var enhancedContext = await AddKnowledge(instruction, "waf", context);
+            return await CallFunction(PMSkills.Readme);
+        }
+        catch (Exception ex)
+        {
+            logger.LogError(ex, "Error creating readme");
+            return "";
+        }
+    }
+}
+
+public interface IManageProducts
+{
+    public Task<string> CreateReadme(string ask);
+}
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Agents/Sandbox.cs b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Sandbox.cs
index 19b0db00553a..306ebc945a49 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Agents/Sandbox.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Agents/Sandbox.cs
@@ -3,7 +3,7 @@
 
 // namespace DevTeam.Backend;
 
-// public sealed class Sandbox : Agent
+// public sealed class Sandbox : AgentBase
 // {
 //     private const string ReminderName = "SandboxRunReminder";
 //     private readonly IManageAzure _azService;
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/AiAgent.cs b/dotnet/samples/dev-team/DevTeam.Backend/AiAgent.cs
new file mode 100644
index 000000000000..427e7bb95f32
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.Backend/AiAgent.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AiAgent.cs
+
+using Microsoft.AutoGen.Core;
+
+namespace DevTeam.Agents;
+
+public class AiAgent<T> : Agent
+{
+    public AiAgent(AgentsMetadata eventTypes, ILogger<AiAgent<T>> logger) : base(eventTypes, logger)
+    {
+    }
+
+    protected async Task AddKnowledge(string instruction, string v)
+    {
+        throw new NotImplementedException();
+    }
+
+    protected async Task<string> CallFunction(string prompt)
+    {
+        throw new NotImplementedException();
+    }
+}
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Consts.cs b/dotnet/samples/dev-team/DevTeam.Backend/Consts.cs
new file mode 100644
index 000000000000..c29f662cdfd7
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Consts.cs
@@ -0,0 +1,9 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Consts.cs
+
+namespace DevTeam.Backend;
+
+public class Consts
+{
+    public const string TopicName = "devteam";
+}
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj
index f13c0cbe4f0d..34030a8817fb 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj
+++ b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj
@@ -1,8 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk.Web">
-
-  <ItemGroup>
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core/Microsoft.AutoGen.Core.csproj" />
-  </ItemGroup>
+<Project Sdk="Microsoft.NET.Sdk.Web">
 
   <PropertyGroup>
         <TargetFramework>net8.0</TargetFramework>
@@ -12,11 +8,9 @@
 
   <ItemGroup>
     <PackageReference Include="Azure.AI.OpenAI" />
+    <PackageReference Include="Microsoft.Extensions.AI" />
     <PackageReference Include="Octokit.Webhooks.AspNetCore" />
     <PackageReference Include="Octokit" />
-    <PackageReference Include="Microsoft.SemanticKernel" />
-    <PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" />
-    <PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" />
     <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" />
     <PackageReference Include="Swashbuckle.AspNetCore" />
     <PackageReference Include="Microsoft.Extensions.Azure" />
@@ -26,13 +20,19 @@
     <PackageReference Include="Azure.Data.Tables" />
     <PackageReference Include="Azure.Identity" />
     <PackageReference Include="System.IdentityModel.Tokens.Jwt" />
+    <PackageReference Include="Google.Protobuf" />
+    <PackageReference Include="Grpc.Tools" PrivateAssets="All" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj" />
+    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
+    <ProjectReference Include="..\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj" />
   </ItemGroup>
 
   <ItemGroup>
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj" />   
-    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Extensions\Aspire\Microsoft.AutoGen.Extensions.Aspire.csproj" />
-    <ProjectReference Include="..\DevTeam.Shared\DevTeam.Shared.csproj" />
-    <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Extensions\SemanticKernel\Microsoft.AutoGen.Extensions.SemanticKernel.csproj" />
+    <Protobuf Include="..\Protos\messages.proto" Link="Protos\messages.proto" />
+    <Protobuf Include="..\Protos\states.proto" Link="Protos\states.proto" />
   </ItemGroup>
 
 </Project>
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/Models/DevPlan.cs b/dotnet/samples/dev-team/DevTeam.Backend/Models/DevPlan.cs
similarity index 100%
rename from dotnet/samples/dev-team/DevTeam.Shared/Models/DevPlan.cs
rename to dotnet/samples/dev-team/DevTeam.Backend/Models/DevPlan.cs
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/Options/AzureOptions.cs b/dotnet/samples/dev-team/DevTeam.Backend/Options/AzureOptions.cs
similarity index 100%
rename from dotnet/samples/dev-team/DevTeam.Shared/Options/AzureOptions.cs
rename to dotnet/samples/dev-team/DevTeam.Backend/Options/AzureOptions.cs
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/Options/GithubOptions.cs b/dotnet/samples/dev-team/DevTeam.Backend/Options/GithubOptions.cs
similarity index 100%
rename from dotnet/samples/dev-team/DevTeam.Shared/Options/GithubOptions.cs
rename to dotnet/samples/dev-team/DevTeam.Backend/Options/GithubOptions.cs
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Program.cs b/dotnet/samples/dev-team/DevTeam.Backend/Program.cs
index abc37cf12608..a2ba9021c271 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Program.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Program.cs
@@ -2,29 +2,35 @@
 // Program.cs
 
 using Azure.Identity;
-using DevTeam.Backend;
 using DevTeam.Options;
-using Microsoft.AI.DevTeam;
-using Microsoft.AutoGen.Core;
-using Microsoft.AutoGen.Extensions.SemanticKernel;
 using Microsoft.Extensions.Azure;
 using Microsoft.Extensions.Options;
+using Microsoft.AutoGen.Core;
 using Octokit.Webhooks;
 using Octokit.Webhooks.AspNetCore;
+using DevTeam.Backend.Services;
+using DevTeam.Backend.Agents;
+using DevTeam.Backend.Agents.ProductManager;
+using DevTeam.Backend.Agents.DeveloperLead;
+using DevTeam.Backend.Agents.Developer;
+using Microsoft.AutoGen.Core.Grpc;
 
 var builder = WebApplication.CreateBuilder(args);
 
 builder.AddServiceDefaults();
-builder.ConfigureSemanticKernel();
 
 builder.Services.AddHttpClient();
 builder.Services.AddControllers();
 builder.Services.AddSwaggerGen();
 
-builder.AddAgentWorker(builder.Configuration["AGENT_HOST"]!)
+builder.AddGrpcAgentWorker(builder.Configuration["AGENT_HOST"]!)
+    .AddAgentWorker()
     .AddAgent<AzureGenie>(nameof(AzureGenie))
     //.AddAgent<Sandbox>(nameof(Sandbox))
-    .AddAgent<Hubber>(nameof(Hubber));
+    .AddAgent<Hubber>(nameof(Hubber))
+    .AddAgent<Dev>(nameof(Dev))
+    .AddAgent<ProductManager>(nameof(ProductManager))
+    .AddAgent<DeveloperLead>(nameof(DeveloperLead));
 
 builder.Services.AddSingleton<AgentWorker>();
 builder.Services.AddSingleton<WebhookEventProcessor, GithubWebHookProcessor>();
@@ -58,7 +64,7 @@
 
 var app = builder.Build();
 
-app.MapDefaultEndpoints();
+Microsoft.Extensions.Hosting.AspireHostingExtensions.MapDefaultEndpoints(app);
 app.UseRouting()
 .UseEndpoints(endpoints =>
 {
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Services/AzureService.cs b/dotnet/samples/dev-team/DevTeam.Backend/Services/AzureService.cs
index 3c3bbf07a0b7..619da62d6873 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Services/AzureService.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Services/AzureService.cs
@@ -12,7 +12,7 @@
 using DevTeam.Options;
 using Microsoft.Extensions.Options;
 
-namespace DevTeam.Backend;
+namespace DevTeam.Backend.Services;
 
 public class AzureService : IManageAzure
 {
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubAuthService.cs b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubAuthService.cs
index d1a3bb7c08df..ba6b9564b9b5 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubAuthService.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubAuthService.cs
@@ -9,7 +9,7 @@
 using Microsoft.IdentityModel.Tokens;
 using Octokit;
 
-namespace DevTeam.Backend;
+namespace DevTeam.Backend.Services;
 public class GithubAuthService
 {
     private readonly GithubOptions _githubSettings;
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubService.cs b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubService.cs
index 5c6dc2125fa9..1108d42e4017 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubService.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubService.cs
@@ -8,7 +8,7 @@
 using Octokit;
 using Octokit.Helpers;
 
-namespace DevTeam.Backend;
+namespace DevTeam.Backend.Services;
 
 public class GithubService : IManageGithub
 {
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs
index 80660328ecae..7264f5621311 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs
@@ -2,7 +2,7 @@
 // GithubWebHookProcessor.cs
 
 using System.Globalization;
-using DevTeam.Shared;
+using Google.Protobuf;
 using Microsoft.AutoGen.Contracts;
 using Microsoft.AutoGen.Core;
 using Octokit.Webhooks;
@@ -11,12 +11,12 @@
 using Octokit.Webhooks.Events.Issues;
 using Octokit.Webhooks.Models;
 
-namespace DevTeam.Backend;
+namespace DevTeam.Backend.Services;
 
-public sealed class GithubWebHookProcessor(ILogger<GithubWebHookProcessor> logger, AgentWorker client) : WebhookEventProcessor
+public sealed class GithubWebHookProcessor(ILogger<GithubWebHookProcessor> logger, Client client) : WebhookEventProcessor
 {
     private readonly ILogger<GithubWebHookProcessor> _logger = logger;
-    private readonly AgentWorker _client = client;
+    private readonly Client _client = client;
 
     protected override async Task ProcessIssuesWebhookAsync(WebhookHeaders headers, IssuesEvent issuesEvent, IssuesAction action)
     {
@@ -43,7 +43,7 @@ protected override async Task ProcessIssuesWebhookAsync(WebhookHeaders headers,
                 return;
             }
 
-            long? parentNumber = labels.TryGetValue("Parent", out string? value) ? long.Parse(value) : null;
+            long? parentNumber = labels.TryGetValue("Parent", out var value) ? long.Parse(value) : null;
             var skillName = labels.Keys.Where(k => k != "Parent").FirstOrDefault();
 
             if (skillName == null)
@@ -114,15 +114,15 @@ private async Task HandleClosingIssue(long issueNumber, string skillName, string
     {
         var subject = suffix + issueNumber.ToString();
 
-        var evt = (skillName, functionName) switch
+        IMessage evt = (skillName, functionName) switch
         {
-            ("PM", "Readme") => new ReadmeChainClosed { }.ToCloudEvent(subject),
-            ("DevLead", "Plan") => new DevPlanChainClosed { }.ToCloudEvent(subject),
-            ("Developer", "Implement") => new CodeChainClosed { }.ToCloudEvent(subject),
+            ("PM", "Readme") => new ReadmeChainClosed {  },
+            ("DevLead", "Plan") => new DevPlanChainClosed { },
+            ("Developer", "Implement") => new CodeChainClosed { },
             _ => new CloudEvent() // TODO: default event
         };
 
-        await _client.PublishEventAsync(evt);
+        await _client.PublishMessageAsync(evt, Consts.TopicName, subject);
     }
 
     private async Task HandleNewAsk(long issueNumber, string skillName, string functionName, string suffix, string input, string org, string repo)
@@ -132,15 +132,15 @@ private async Task HandleNewAsk(long issueNumber, string skillName, string funct
             _logger.LogInformation("Handling new ask");
             var subject = suffix + issueNumber.ToString();
 
-            var evt = (skillName, functionName) switch
+            IMessage evt = (skillName, functionName) switch
             {
-                ("Do", "It") => new NewAsk { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo }.ToCloudEvent(subject),
-                ("PM", "Readme") => new ReadmeRequested { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo }.ToCloudEvent(subject),
-                ("DevLead", "Plan") => new DevPlanRequested { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo }.ToCloudEvent(subject),
-                ("Developer", "Implement") => new CodeGenerationRequested { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo }.ToCloudEvent(subject),
+                ("Do", "It") => new NewAsk { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo },
+                ("PM", "Readme") => new ReadmeRequested { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo },
+                ("DevLead", "Plan") => new DevPlanRequested { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo },
+                ("Developer", "Implement") => new CodeGenerationRequested { Ask = input, IssueNumber = issueNumber, Org = org, Repo = repo },
                 _ => new CloudEvent()
             };
-            await _client.PublishEventAsync(evt);
+            await _client.PublishMessageAsync(evt, Consts.TopicName, subject);
         }
         catch (Exception ex)
         {
diff --git a/dotnet/samples/dev-team/DevTeam.ServiceDefaults/DevTeam.ServiceDefaults.csproj b/dotnet/samples/dev-team/DevTeam.ServiceDefaults/DevTeam.ServiceDefaults.csproj
new file mode 100644
index 000000000000..2388aea655b8
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.ServiceDefaults/DevTeam.ServiceDefaults.csproj
@@ -0,0 +1,22 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <IsAspireSharedProject>true</IsAspireSharedProject>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <FrameworkReference Include="Microsoft.AspNetCore.App" />
+
+    <PackageReference Include="Microsoft.Extensions.Http.Resilience" />
+    <PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
+    <PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
+    <PackageReference Include="OpenTelemetry.Extensions.Hosting" />
+    <PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
+    <PackageReference Include="OpenTelemetry.Instrumentation.Http" />
+    <PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
+  </ItemGroup>
+
+</Project>
diff --git a/dotnet/samples/dev-team/DevTeam.ServiceDefaults/Extensions.cs b/dotnet/samples/dev-team/DevTeam.ServiceDefaults/Extensions.cs
new file mode 100644
index 000000000000..adb2952115ff
--- /dev/null
+++ b/dotnet/samples/dev-team/DevTeam.ServiceDefaults/Extensions.cs
@@ -0,0 +1,120 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Extensions.cs
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Diagnostics.HealthChecks;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Diagnostics.HealthChecks;
+using Microsoft.Extensions.Logging;
+using OpenTelemetry;
+using OpenTelemetry.Metrics;
+using OpenTelemetry.Trace;
+
+namespace Microsoft.Extensions.Hosting;
+// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
+// This project should be referenced by each service project in your solution.
+// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
+public static class Extensions
+{
+    public static TBuilder AddServiceDefaults<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+    {
+        builder.ConfigureOpenTelemetry();
+
+        builder.AddDefaultHealthChecks();
+
+        builder.Services.AddServiceDiscovery();
+
+        builder.Services.ConfigureHttpClientDefaults(http =>
+        {
+            // Turn on resilience by default
+            http.AddStandardResilienceHandler();
+
+            // Turn on service discovery by default
+            http.AddServiceDiscovery();
+        });
+
+        // Uncomment the following to restrict the allowed schemes for service discovery.
+        // builder.Services.Configure<ServiceDiscoveryOptions>(options =>
+        // {
+        //     options.AllowedSchemes = ["https"];
+        // });
+
+        return builder;
+    }
+
+    public static TBuilder ConfigureOpenTelemetry<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+    {
+        builder.Logging.AddOpenTelemetry(logging =>
+        {
+            logging.IncludeFormattedMessage = true;
+            logging.IncludeScopes = true;
+        });
+
+        builder.Services.AddOpenTelemetry()
+            .WithMetrics(metrics =>
+            {
+                metrics.AddAspNetCoreInstrumentation()
+                    .AddHttpClientInstrumentation()
+                    .AddRuntimeInstrumentation();
+            })
+            .WithTracing(tracing =>
+            {
+                tracing.AddSource(builder.Environment.ApplicationName)
+                    .AddAspNetCoreInstrumentation()
+                    // Uncomment the following line to enable gRPC instrumentation (requires the OpenTelemetry.Instrumentation.GrpcNetClient package)
+                    //.AddGrpcClientInstrumentation()
+                    .AddHttpClientInstrumentation();
+            });
+
+        builder.AddOpenTelemetryExporters();
+
+        return builder;
+    }
+
+    private static TBuilder AddOpenTelemetryExporters<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+    {
+        var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
+
+        if (useOtlpExporter)
+        {
+            builder.Services.AddOpenTelemetry().UseOtlpExporter();
+        }
+
+        // Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
+        //if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
+        //{
+        //    builder.Services.AddOpenTelemetry()
+        //       .UseAzureMonitor();
+        //}
+
+        return builder;
+    }
+
+    public static TBuilder AddDefaultHealthChecks<TBuilder>(this TBuilder builder) where TBuilder : IHostApplicationBuilder
+    {
+        builder.Services.AddHealthChecks()
+            // Add a default liveness check to ensure app is responsive
+            .AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
+
+        return builder;
+    }
+
+    public static WebApplication MapDefaultEndpoints(this WebApplication app)
+    {
+        // Adding health checks endpoints to applications in non-development environments has security implications.
+        // See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
+        if (app.Environment.IsDevelopment())
+        {
+            // All health checks must pass for app to be considered ready to accept traffic after starting
+            app.MapHealthChecks("/health");
+
+            // Only health checks tagged with the "live" tag must pass for app to be considered alive
+            app.MapHealthChecks("/alive", new HealthCheckOptions
+            {
+                Predicate = r => r.Tags.Contains("live")
+            });
+        }
+
+        return app;
+    }
+}
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj b/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj
deleted file mode 100644
index 674bba3b13ec..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Shared/DevTeam.Shared.csproj
+++ /dev/null
@@ -1,27 +0,0 @@
-<Project Sdk="Microsoft.NET.Sdk">
-
-  <ItemGroup>
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core/Microsoft.AutoGen.Core.csproj" />
-  </ItemGroup>
-
-  <PropertyGroup>
-        <TargetFramework>net8.0</TargetFramework>
-    <ImplicitUsings>enable</ImplicitUsings>
-    <Nullable>enable</Nullable>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <PackageReference Include="Azure.AI.OpenAI" />
-    <PackageReference Include="Microsoft.SemanticKernel" />
-    <PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" />
-    <PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" />
-    <PackageReference Include="Google.Protobuf" />
-    <PackageReference Include="Grpc.Tools" PrivateAssets="All" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <Protobuf Include="..\Protos\messages.proto" Link="Protos\messages.proto" />
-    <Protobuf Include="..\Protos\states.proto" Link="Protos\states.proto" />
-  </ItemGroup>
-
-</Project>
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/EventExtensions.cs b/dotnet/samples/dev-team/DevTeam.Shared/EventExtensions.cs
deleted file mode 100644
index bbf51dcdea6f..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Shared/EventExtensions.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// EventExtensions.cs
-
-using System.Globalization;
-using Microsoft.AutoGen.Contracts;
-
-namespace DevTeam;
-
-public static class EventExtensions
-{
-    public static GithubContext ToGithubContext(this Event evt)
-    {
-        ArgumentNullException.ThrowIfNull(evt);
-        var data = new Dictionary<string, string>();// JsonSerializer.Deserialize<Dictionary<string,string>>(evt.Data);
-        return new GithubContext
-        {
-            Org = data?["org"] ?? "",
-            Repo = data?["repo"] ?? "",
-            IssueNumber = data?.TryParseLong("issueNumber") ?? default,
-            ParentNumber = data?.TryParseLong("parentNumber")
-        };
-    }
-
-    public static Dictionary<string, string> ToData(this Event evt)
-    {
-        ArgumentNullException.ThrowIfNull(evt);
-        return //JsonSerializer.Deserialize<Dictionary<string,string>>(evt.Data) ??
-                new Dictionary<string, string>();
-    }
-    public static Dictionary<string, string> ToData(this GithubContext context)
-    {
-        ArgumentNullException.ThrowIfNull(context);
-
-        return new Dictionary<string, string> {
-            { "org", context.Org },
-            { "repo", context.Repo },
-            { "issueNumber", $"{context.IssueNumber}" },
-            { "parentNumber", context.ParentNumber?.ToString(CultureInfo.InvariantCulture) ?? "" }
-        };
-    }
-}
-
-public class GithubContext
-{
-    public required string Org { get; set; }
-    public required string Repo { get; set; }
-    public long IssueNumber { get; set; }
-    public long? ParentNumber { get; set; }
-
-    public string Subject => $"{Org}/{Repo}/{IssueNumber}";
-}
diff --git a/dotnet/samples/dev-team/DevTeam.Shared/ParseExtensions.cs b/dotnet/samples/dev-team/DevTeam.Shared/ParseExtensions.cs
deleted file mode 100644
index c4681513dd10..000000000000
--- a/dotnet/samples/dev-team/DevTeam.Shared/ParseExtensions.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// ParseExtensions.cs
-
-namespace DevTeam;
-
-public static class ParseExtensions
-{
-    public static long TryParseLong(this Dictionary<string, string> data, string key)
-    {
-        ArgumentNullException.ThrowIfNull(data);
-
-        if (data.TryGetValue(key, out string? value) && !string.IsNullOrEmpty(value) && long.TryParse(value, out var result))
-        {
-            return result;
-        }
-        return default;
-    }
-}
diff --git a/dotnet/samples/dev-team/Protos/messages.proto b/dotnet/samples/dev-team/Protos/messages.proto
index 23db04a439f1..05861668b966 100644
--- a/dotnet/samples/dev-team/Protos/messages.proto
+++ b/dotnet/samples/dev-team/Protos/messages.proto
@@ -2,7 +2,7 @@ syntax = "proto3";
 
 package devteam;
 
-option csharp_namespace = "DevTeam.Shared";
+option csharp_namespace = "DevTeam";
 
 message NewAsk {
   string org = 1;
diff --git a/dotnet/samples/dev-team/Protos/states.proto b/dotnet/samples/dev-team/Protos/states.proto
index 4aaec1090639..b093aa1ad2ad 100644
--- a/dotnet/samples/dev-team/Protos/states.proto
+++ b/dotnet/samples/dev-team/Protos/states.proto
@@ -2,7 +2,7 @@ syntax = "proto3";
 
 package devteam;
 
-option csharp_namespace = "DevTeam.Shared";
+option csharp_namespace = "DevTeam";
 
 
 message DeveloperState {
diff --git a/dotnet/samples/dev-team/dev team.sln b/dotnet/samples/dev-team/dev team.sln
deleted file mode 100644
index f8a7aeacd924..000000000000
--- a/dotnet/samples/dev-team/dev team.sln	
+++ /dev/null
@@ -1,49 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.11.35327.3
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.AgentHost", "DevTeam.AgentHost\DevTeam.AgentHost.csproj", "{A6FC8B01-A177-4690-BD16-73EE3D0C06A0}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Backend", "DevTeam.Backend\DevTeam.Backend.csproj", "{2D4BAD10-85F3-4E4B-B759-13449A212A96}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Agents", "DevTeam.Agents\DevTeam.Agents.csproj", "{A51CE540-72B0-4271-B63D-A30CAB61C227}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.AppHost", "DevTeam.AppHost\DevTeam.AppHost.csproj", "{2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevTeam.Shared", "DevTeam.Shared\DevTeam.Shared.csproj", "{557701A5-35D8-4CE3-BA75-D5412B4227F5}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Release|Any CPU = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A6FC8B01-A177-4690-BD16-73EE3D0C06A0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2D4BAD10-85F3-4E4B-B759-13449A212A96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2D4BAD10-85F3-4E4B-B759-13449A212A96}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2D4BAD10-85F3-4E4B-B759-13449A212A96}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2D4BAD10-85F3-4E4B-B759-13449A212A96}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A51CE540-72B0-4271-B63D-A30CAB61C227}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A51CE540-72B0-4271-B63D-A30CAB61C227}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A51CE540-72B0-4271-B63D-A30CAB61C227}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A51CE540-72B0-4271-B63D-A30CAB61C227}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2B8A3C64-9F4E-4CC5-9466-AFFD8E676D2E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{557701A5-35D8-4CE3-BA75-D5412B4227F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{557701A5-35D8-4CE3-BA75-D5412B4227F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{557701A5-35D8-4CE3-BA75-D5412B4227F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{557701A5-35D8-4CE3-BA75-D5412B4227F5}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {DE04DB59-B8CD-4305-875B-E71442345CCF}
-	EndGlobalSection
-EndGlobal
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/InferenceAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/InferenceAgent.cs
index bfcd7c6cc179..750643846fac 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/InferenceAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/InferenceAgent.cs
@@ -5,10 +5,9 @@
 using Microsoft.Extensions.AI;
 namespace Microsoft.AutoGen.Agents;
 public abstract class InferenceAgent<T>(
-    IAgentWorker worker,
-    EventTypes typeRegistry,
+    AgentsMetadata typeRegistry,
     IChatClient client)
-    : Agent(worker, typeRegistry)
+    : Agent(typeRegistry)
     where T : IMessage, new()
 {
     protected IChatClient ChatClient { get; } = client;
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs
index 210c2054686e..1c1509d263f8 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/AIAgent/SKAiAgent.cs
@@ -9,11 +9,9 @@
 
 namespace Microsoft.AutoGen.Agents;
 public abstract class SKAiAgent<T>(
-    IAgentWorker worker,
     ISemanticTextMemory memory,
     Kernel kernel,
     AgentsMetadata typeRegistry) : Agent(
-        worker,
         typeRegistry) where T : class, new()
 {
     protected AgentState<T> _state = new();
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs
index 03b654741704..2f71d2976bc1 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/ConsoleAgent.cs
@@ -13,11 +13,11 @@ public abstract class ConsoleAgent : IOAgent,
 {
 
     // instead of the primary constructor above, make a constructr here that still calls the base constructor
-    public ConsoleAgent(IAgentWorker worker, [FromKeyedServices("EventTypes")] AgentsMetadata typeRegistry) : base(worker, typeRegistry)
+    public ConsoleAgent([FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : base(typeRegistry)
     {
         _route = "console";
     }
-    public override async Task Handle(Input item)
+    public override async Task Handle(Input item, CancellationToken cancellationToken)
     {
         Console.WriteLine("Please enter input:");
         string content = Console.ReadLine() ?? string.Empty;
@@ -31,7 +31,7 @@ public override async Task Handle(Input item)
         await PublishMessageAsync(evt);
     }
 
-    public override async Task Handle(Output item)
+    public override async Task Handle(Output item, CancellationToken cancellationToken)
     {
         // Assuming item has a property `Content` that we want to write to the console
         Console.WriteLine(item.Message);
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
index dced31aac23a..cd0fa71eca0d 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
@@ -10,7 +10,7 @@ namespace Microsoft.AutoGen.Agents;
 public interface IHandleConsole : IHandle<Output>, IHandle<Input>
 {
     AgentId AgentId { get; }
-    ValueTask PublishMessageAsync<T>(T message, string? source = null, CancellationToken token = default) where T : IMessage;
+    ValueTask PublishMessageAsync<T>(T message, string? source = null, string? key = null, CancellationToken token = default) where T : IMessage;
 
     async Task IHandle<Output>.Handle(Output item, CancellationToken cancellationToken)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/FileAgent/FileAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/FileAgent/FileAgent.cs
index ddab8a61ed58..a1d385286937 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/FileAgent/FileAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/FileAgent/FileAgent.cs
@@ -9,16 +9,15 @@ namespace Microsoft.AutoGen.Agents;
 
 [TopicSubscription("FileIO")]
 public abstract class FileAgent(
-    IAgentWorker worker,
-    [FromKeyedServices("EventTypes")] EventTypes typeRegistry,
+    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry,
     string inputPath = "input.txt",
     string outputPath = "output.txt"
-    ) : IOAgent(worker, typeRegistry),
+    ) : IOAgent(typeRegistry),
         IUseFiles,
         IHandle<Input>,
         IHandle<Output>
 {
-    public override async Task Handle(Input item)
+    public override async Task Handle(Input item, CancellationToken cancellationToken = default)
     {
         // validate that the file exists
         if (!File.Exists(inputPath))
@@ -46,7 +45,7 @@ public override async Task Handle(Input item)
         };
         await PublishMessageAsync(evt);
     }
-    public override async Task Handle(Output item)
+    public override async Task Handle(Output item, CancellationToken cancellationToken = default)
     {
         using (var writer = new StreamWriter(outputPath, append: true))
         {
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/IOAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/IOAgent.cs
index e2b53d694885..6f2ab5a76dba 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/IOAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/IOAgent.cs
@@ -5,11 +5,11 @@
 using Microsoft.AutoGen.Core;
 namespace Microsoft.AutoGen.Agents;
 
-public abstract class IOAgent(IAgentWorker worker, EventTypes eventTypes) : Agent(worker, eventTypes)
+public abstract class IOAgent(AgentsMetadata eventTypes) : Agent(eventTypes)
 {
     public string _route = "base";
 
-    public virtual async Task Handle(Input item)
+    public virtual async Task Handle(Input item, CancellationToken cancellationToken)
     {
 
         var evt = new InputProcessed
@@ -19,7 +19,7 @@ public virtual async Task Handle(Input item)
         await PublishMessageAsync(evt);
     }
 
-    public virtual async Task Handle(Output item)
+    public virtual async Task Handle(Output item, CancellationToken cancellationToken)
     {
         var evt = new OutputWritten
         {
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/WebAPIAgent/WebAPIAgent.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/WebAPIAgent/WebAPIAgent.cs
index 3e43096bee29..a94d8d1813e6 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/WebAPIAgent/WebAPIAgent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/WebAPIAgent/WebAPIAgent.cs
@@ -18,10 +18,9 @@ public abstract class WebAPIAgent : IOAgent,
 
     public WebAPIAgent(
     IAgentWorker worker,
-    [FromKeyedServices("EventTypes")] EventTypes typeRegistry,
+    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry,
     ILogger<WebAPIAgent> logger,
     string url = "/agents/webio") : base(
-        worker,
         typeRegistry)
     {
         _url = url;
@@ -53,7 +52,7 @@ public WebAPIAgent(
         app.Run();
     }
 
-    public override async Task Handle(Input item)
+    public override async Task Handle(Input item, CancellationToken cancellationToken = default)
     {
         // Process the input (this is a placeholder, replace with actual processing logic)
         await ProcessInput(item.Message);
@@ -65,7 +64,7 @@ public override async Task Handle(Input item)
         await PublishMessageAsync(evt);
     }
 
-    public override async Task Handle(Output item)
+    public override async Task Handle(Output item, CancellationToken cancellationToken = default)
     {
         // Assuming item has a property `Content` that we want to return in the response
         var evt = new OutputWritten
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 71209d4ed4d7..29d3be57d4c2 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -216,7 +216,7 @@ await WriteChannelAsync(new Message
             {
                 var subscriptionRequest = new Message
                 {
-                    AddSubscriptionRequest = new AddSubscriptionRequest
+                    SubscriptionRequest = new SubscriptionRequest
                     {
                         RequestId = Guid.NewGuid().ToString(),
                         Subscription = new Subscription
@@ -234,7 +234,7 @@ await WriteChannelAsync(new Message
                 {
                     subscriptionRequest = new Message
                     {
-                        AddSubscriptionRequest = new AddSubscriptionRequest
+                        SubscriptionRequest = new SubscriptionRequest
                         {
                             RequestId = Guid.NewGuid().ToString(),
                             Subscription = new Subscription
@@ -397,7 +397,17 @@ public async ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken
         }
     }
 
-    public ValueTask<List<string>> GetSubscriptionsAsync(Type type)
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
+    {
+        throw new NotImplementedException();
+    }
+
+    public ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+
+    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
     {
         throw new NotImplementedException();
     }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index fb7e964381c5..50a29203d4c7 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -49,10 +49,8 @@ protected Agent(
     public static void Initialize(IAgentWorker worker, Agent agent)
     {
         agent.Worker = worker;
-        agent.Start().ContinueWith(async startTask =>
-        {
-            await agent.AddImplicitSubscriptionsAsync();
-        }, TaskScheduler.Default);
+        agent.Start().Wait();
+        agent.AddImplicitSubscriptionsAsync().AsTask().Wait();
     }
 
     private async ValueTask AddImplicitSubscriptionsAsync()
@@ -65,7 +63,7 @@ private async ValueTask AddImplicitSubscriptionsAsync()
 
         foreach (var topicType in topicTypes)
         {
-            var subscriptionRequest = new AddSubscriptionRequest
+            var subscriptionRequest = new SubscriptionRequest
             {
                 RequestId = Guid.NewGuid().ToString(),
                 Subscription = new Subscription
@@ -78,7 +76,7 @@ private async ValueTask AddImplicitSubscriptionsAsync()
                 }
             };
             // explicitly wait for this to complete
-            await Worker.SendMessageAsync(new Message { AddSubscriptionRequest = subscriptionRequest }).ConfigureAwait(true);
+            await Worker.SendMessageAsync(new Message { SubscriptionRequest = subscriptionRequest }).ConfigureAwait(true);
         }
 
         // using reflection, find all methods that Handle<T> and subscribe to the topic T
@@ -175,7 +173,7 @@ await this.InvokeWithActivityAsync(
                 break;
         }
     }
-    public async ValueTask<List<string>> GetSubscriptionsAsync()
+    public async ValueTask<List<Subscription>> GetSubscriptionsAsync()
     {
         return await Worker.GetSubscriptionsAsync(GetType()).ConfigureAwait(false);
     }
@@ -183,7 +181,7 @@ public List<string> Subscribe(string topic)
     {
         Message message = new()
         {
-            AddSubscriptionRequest = new()
+            SubscriptionRequest = new()
             {
                 RequestId = Guid.NewGuid().ToString(),
                 Subscription = new Subscription
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 700dc20b0885..8de12f77bb4a 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -2,56 +2,41 @@
 // AgentWorker.cs
 
 using System.Collections.Concurrent;
-using System.Diagnostics;
 using System.Threading.Channels;
 using Microsoft.AutoGen.Contracts;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
 
 namespace Microsoft.AutoGen.Core;
 
 /// <summary>
 /// Represents a worker that manages agents and handles messages.
 /// </summary>
-public class AgentWorker : IHostedService, IAgentWorker
+/// <remarks>
+/// Initializes a new instance of the <see cref="AgentWorker"/> class.
+/// </remarks>
+/// <param name="hostApplicationLifetime">The application lifetime.</param>
+/// <param name="serviceProvider">The service provider.</param>
+/// <param name="configuredAgentTypes">The configured agent types.</param>
+public class AgentWorker(
+    IHostApplicationLifetime hostApplicationLifetime,
+    IServiceProvider serviceProvider,
+    [FromKeyedServices("AgentTypes")] IEnumerable<Tuple<string, Type>> configuredAgentTypes) : IHostedService, IAgentWorker
 {
     private readonly ConcurrentDictionary<string, Type> _agentTypes = new();
     private readonly ConcurrentDictionary<(string Type, string Key), Agent> _agents = new();
-    private readonly ILogger<AgentWorker> _logger;
     private readonly Channel<object> _mailbox = Channel.CreateUnbounded<object>();
     private readonly ConcurrentDictionary<string, AgentState> _agentStates = new();
     private readonly ConcurrentDictionary<string, (Agent Agent, string OriginalRequestId)> _pendingClientRequests = new();
-    private readonly CancellationTokenSource _shutdownCts;
-    public IServiceProvider ServiceProvider { get; }
-    private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes;
-    private readonly DistributedContextPropagator _distributedContextPropagator;
+    private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping);
+    public IServiceProvider ServiceProvider { get; } = serviceProvider;
+    private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes = configuredAgentTypes;
+    private readonly ConcurrentDictionary<string, List<Subscription>> _subscriptionsByAgentType = new();
+    private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
     private readonly CancellationTokenSource _shutdownCancellationToken = new();
     private Task? _mailboxTask;
     private readonly object _channelLock = new();
 
-    /// <summary>
-    /// Initializes a new instance of the <see cref="AgentWorker"/> class.
-    /// </summary>
-    /// <param name="hostApplicationLifetime">The application lifetime.</param>
-    /// <param name="serviceProvider">The service provider.</param>
-    /// <param name="configuredAgentTypes">The configured agent types.</param>
-    /// <param name="logger">The logger.</param>
-    /// <param name="distributedContextPropagator">The distributed context propagator.</param>
-    public AgentWorker(
-        IHostApplicationLifetime hostApplicationLifetime,
-        IServiceProvider serviceProvider,
-        [FromKeyedServices("AgentTypes")] IEnumerable<Tuple<string, Type>> configuredAgentTypes,
-        ILogger<AgentWorker> logger,
-        DistributedContextPropagator distributedContextPropagator)
-    {
-        _logger = logger;
-        ServiceProvider = serviceProvider;
-        _configuredAgentTypes = configuredAgentTypes;
-        _distributedContextPropagator = distributedContextPropagator;
-        _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(hostApplicationLifetime.ApplicationStopping);
-    }
-
     /// <inheritdoc />
     public async ValueTask PublishEventAsync(CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
@@ -129,10 +114,10 @@ public async Task RunMessagePump()
                             agentToInvoke.ReceiveMessage(msg);
                         }
                         break;
-                    case Message msg when msg.AddSubscriptionRequest != null:
-                        await AddSubscriptionRequestAsync(msg.AddSubscriptionRequest).ConfigureAwait(true);
+                    case Message msg when msg.SubscriptionRequest != null:
+                        await SubscribeAsync(msg.SubscriptionRequest).ConfigureAwait(true);
                         break;
-                    case Message msg when msg.AddSubscriptionResponse != null:
+                    case Message msg when msg.SubscriptionResponse != null:
                         break;
                     case Message msg when msg.RegisterAgentTypeResponse != null:
                         break;
@@ -149,22 +134,19 @@ public async Task RunMessagePump()
             }
         }
     }
-    private async ValueTask AddSubscriptionRequestAsync(AddSubscriptionRequest subscription)
+    public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest subscription, CancellationToken cancellationToken = default)
     {
         var topic = subscription.Subscription.TypeSubscription.TopicType;
         var agentType = subscription.Subscription.TypeSubscription.AgentType;
-        _subscriptionsByAgentType[agentType] = subscription.Subscription;
+        _subscriptionsByAgentType.GetOrAdd(key: agentType, _ => []).Add(subscription.Subscription);
         _subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
-        Message response = new()
+        var response = new SubscriptionResponse
         {
-            AddSubscriptionResponse = new()
-            {
-                RequestId = subscription.RequestId,
-                Error = "",
-                Success = true
-            }
+            RequestId = subscription.RequestId,
+            Error = "",
+            Success = true
         };
-        await _mailbox.Writer.WriteAsync(response).ConfigureAwait(false);
+        return response;
     }
 
     public async Task StartAsync(CancellationToken cancellationToken)
@@ -243,7 +225,15 @@ private Agent GetOrActivateAgent(AgentId agentId)
         return agent;
     }
 
-    public ValueTask<List<string>> GetSubscriptionsAsync(Type type)
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
+    {
+        if (_subscriptionsByAgentType.TryGetValue(type.Name, out var subscriptions))
+        {
+            return new ValueTask<List<Subscription>>(subscriptions);
+        }
+        return new ValueTask<List<Subscription>>([]);
+    }
+    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
     {
         throw new NotImplementedException();
     }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
index ad22df9cd08a..a8be598aa7ca 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
@@ -12,5 +12,7 @@ public interface IAgentWorker
     ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default);
     ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default);
     ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
-    ValueTask<List<string>> GetSubscriptionsAsync(Type type);
+    ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
+    ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
+    ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
index 7719a294fa48..fec7fef60cc5 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -14,7 +14,9 @@ public class UninitializedAgentWorker() : IAgentWorker
     public ValueTask SendRequestAsync(Agent agent, RpcRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
-    public ValueTask<List<string>> GetSubscriptionsAsync(Type type) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public class AgentInitalizedIncorrectlyException(string message) : Exception(message)
     {
     }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
index dd7263729378..3d7044f96d87 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
@@ -11,6 +11,6 @@ public interface IGateway : IGrainObserver
     ValueTask StoreAsync(Contracts.AgentState value);
     ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId);
     ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request);
-    ValueTask<AddSubscriptionResponse> AddSubscriptionAsync(AddSubscriptionRequest request);
+    ValueTask<SubscriptionResponse> AddSubscriptionAsync(SubscriptionRequest request);
     Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
index ffb053956ffc..31ff29a0600e 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
@@ -67,14 +67,14 @@ public interface IRegistry
     /// </summary>
     /// <param name="request">The subscription request.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    ValueTask SubscribeAsync(AddSubscriptionRequest request);
+    ValueTask SubscribeAsync(SubscriptionRequest request);
 
     /// <summary>
     /// Unsubscribes an agent from a topic.
     /// </summary>
     /// <param name="request">The unsubscription request.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    ValueTask UnsubscribeAsync(AddSubscriptionRequest request); // TODO: This should have its own request type.
+    ValueTask UnsubscribeAsync(SubscriptionRequest request); // TODO: This should have its own request type.
 
     /// <summary>
     /// Gets the subscriptions for a specified agent type.
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 7442dbb0fae5..fe76aaa6fe99 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -102,12 +102,12 @@ public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(Registe
             };
         }
     }
-    public async ValueTask<AddSubscriptionResponse> AddSubscriptionAsync(AddSubscriptionRequest request)
+    public async ValueTask<SubscriptionResponse> AddSubscriptionAsync(SubscriptionRequest request)
     {
         try
         {
             await _gatewayRegistry.SubscribeAsync(request).ConfigureAwait(true);
-            return new AddSubscriptionResponse
+            return new SubscriptionResponse
             {
                 Success = true,
                 RequestId = request.RequestId
@@ -115,7 +115,7 @@ public async ValueTask<AddSubscriptionResponse> AddSubscriptionAsync(AddSubscrip
         }
         catch (Exception ex)
         {
-            return new AddSubscriptionResponse
+            return new SubscriptionResponse
             {
                 Success = false,
                 RequestId = request.RequestId,
@@ -184,8 +184,8 @@ internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Mess
             case Message.MessageOneofCase.RegisterAgentTypeRequest:
                 await RegisterAgentTypeAsync(connection, message.RegisterAgentTypeRequest);
                 break;
-            case Message.MessageOneofCase.AddSubscriptionRequest:
-                await AddSubscriptionAsync(connection, message.AddSubscriptionRequest);
+            case Message.MessageOneofCase.SubscriptionRequest:
+                await AddSubscriptionAsync(connection, message.SubscriptionRequest);
                 break;
             default:
                 // if it wasn't recognized return bad request
@@ -320,7 +320,7 @@ private static async ValueTask RespondBadRequestAsync(GrpcWorkerConnection conne
     {
         throw new RpcException(new Status(StatusCode.InvalidArgument, error));
     }
-    private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, AddSubscriptionRequest request)
+    private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, SubscriptionRequest request)
     {
         var topic = "";
         var agentType = "";
@@ -337,10 +337,10 @@ private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, Ad
         _subscriptionsByAgentType[agentType] = request.Subscription;
         _subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
         await _subscriptions.SubscribeAsync(topic, agentType);
-        //var response = new AddSubscriptionResponse { RequestId = request.RequestId, Error = "", Success = true };
+        //var response = new SubscriptionResponse { RequestId = request.RequestId, Error = "", Success = true };
         Message response = new()
         {
-            AddSubscriptionResponse = new()
+            SubscriptionResponse = new()
             {
                 RequestId = request.RequestId,
                 Error = "",
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index 156fab2ef191..56c5d919c3f3 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -42,7 +42,7 @@ public override async Task<SaveStateResponse> SaveState(AgentState request, Serv
             Success = true // TODO: Implement error handling
         };
     }
-    public override async Task<AddSubscriptionResponse> AddSubscription(AddSubscriptionRequest request, ServerCallContext context)
+    public override async Task<SubscriptionResponse> AddSubscription(SubscriptionRequest request, ServerCallContext context)
     {
         request.RequestId = context.Peer;
         return await Gateway.AddSubscriptionAsync(request);
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index d2b03e9e7e43..fab3c8b6eb63 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -172,7 +172,7 @@ private WorkerState GetOrAddWorker(IGateway worker)
         return null;
     }
 
-    public async ValueTask SubscribeAsync(AddSubscriptionRequest sub)
+    public async ValueTask SubscribeAsync(SubscriptionRequest sub)
     {
         switch (sub.Subscription.SubscriptionCase)
         {
@@ -206,7 +206,7 @@ public async ValueTask SubscribeAsync(AddSubscriptionRequest sub)
         }
         await state.WriteStateAsync().ConfigureAwait(false);
     }
-    public async ValueTask UnsubscribeAsync(AddSubscriptionRequest request)
+    public async ValueTask UnsubscribeAsync(SubscriptionRequest request)
     {
         throw new NotImplementedException();
     }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionRequestSurrogate.cs
similarity index 51%
rename from dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
rename to dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionRequestSurrogate.cs
index e732c3ffc982..f273b0b2347c 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionRequestSurrogate.cs
@@ -1,12 +1,12 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
-// AddSubscriptionRequestSurrogate.cs
+// SubscriptionRequestSurrogate.cs
 
 using Microsoft.AutoGen.Contracts;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
 
 [GenerateSerializer]
-public struct AddSubscriptionRequestSurrogate
+public struct SubscriptionRequestSurrogate
 {
     [Id(0)]
     public string RequestId;
@@ -15,13 +15,13 @@ public struct AddSubscriptionRequestSurrogate
 }
 
 [RegisterConverter]
-public sealed class AddSubscriptionRequestSurrogateConverter :
-    IConverter<AddSubscriptionRequest, AddSubscriptionRequestSurrogate>
+public sealed class SubscriptionRequestSurrogateConverter :
+    IConverter<SubscriptionRequest, SubscriptionRequestSurrogate>
 {
-    public AddSubscriptionRequest ConvertFromSurrogate(
-        in AddSubscriptionRequestSurrogate surrogate)
+    public SubscriptionRequest ConvertFromSurrogate(
+        in SubscriptionRequestSurrogate surrogate)
     {
-        var request = new AddSubscriptionRequest()
+        var request = new SubscriptionRequest()
         {
             RequestId = surrogate.RequestId,
             Subscription = surrogate.Subscription
@@ -29,9 +29,9 @@ public AddSubscriptionRequest ConvertFromSurrogate(
         return request;
     }
 
-    public AddSubscriptionRequestSurrogate ConvertToSurrogate(
-        in AddSubscriptionRequest value) =>
-        new AddSubscriptionRequestSurrogate
+    public SubscriptionRequestSurrogate ConvertToSurrogate(
+        in SubscriptionRequest value) =>
+        new SubscriptionRequestSurrogate
         {
             RequestId = value.RequestId,
             Subscription = value.Subscription
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionResponseSurrogate.cs
similarity index 53%
rename from dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
rename to dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionResponseSurrogate.cs
index d35a3c5f6f89..5e8938643dcc 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionResponseSurrogate.cs
@@ -1,12 +1,12 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
-// AddSubscriptionResponseSurrogate.cs
+// SubscriptionResponseSurrogate.cs
 
 using Microsoft.AutoGen.Contracts;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
 
 [GenerateSerializer]
-public struct AddSubscriptionResponseSurrogate
+public struct SubscriptionResponseSurrogate
 {
     [Id(0)]
     public string RequestId;
@@ -17,21 +17,21 @@ public struct AddSubscriptionResponseSurrogate
 }
 
 [RegisterConverter]
-public sealed class AddSubscriptionResponseSurrogateConverter :
-    IConverter<AddSubscriptionResponse, AddSubscriptionResponseSurrogate>
+public sealed class SubscriptionResponseSurrogateConverter :
+    IConverter<SubscriptionResponse, SubscriptionResponseSurrogate>
 {
-    public AddSubscriptionResponse ConvertFromSurrogate(
-        in AddSubscriptionResponseSurrogate surrogate) =>
-        new AddSubscriptionResponse
+    public SubscriptionResponse ConvertFromSurrogate(
+        in SubscriptionResponseSurrogate surrogate) =>
+        new SubscriptionResponse
         {
             RequestId = surrogate.RequestId,
             Success = surrogate.Success,
             Error = surrogate.Error
         };
 
-    public AddSubscriptionResponseSurrogate ConvertToSurrogate(
-        in AddSubscriptionResponse value) =>
-        new AddSubscriptionResponseSurrogate
+    public SubscriptionResponseSurrogate ConvertToSurrogate(
+        in SubscriptionResponse value) =>
+        new SubscriptionResponseSurrogate
         {
             RequestId = value.RequestId,
             Success = value.Success,
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index eda96fad37b8..2fb8a3a8e638 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -46,6 +46,8 @@ public async Task Agent_ShouldInitializeCorrectly()
         var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
         Agent.Initialize(worker, agent);
         Assert.Equal("AgentWorker", agent.Worker.GetType().Name);
+        var subscriptions = await agent.GetSubscriptionsAsync();
+        Assert.Equal(2, subscriptions.Count);
     }
 
     [Fact]
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 6c37c492ab33..841264a1230a 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -9,6 +9,7 @@
 using Microsoft.Extensions.Logging;
 using Moq;
 using Tests.Events;
+using NewMessageReceived = Tests.Events.NewMessageReceived;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Tests;
 [Collection(ClusterCollection.Name)]
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
index 1b3c10350a6c..655a14cb418a 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
@@ -10,7 +10,7 @@
 namespace Microsoft.AutoGen.Runtime.Grpc.Tests;
 
 [TopicSubscription("gh-gh-gh")]
-public class PBAgent([FromKeyedServices("EventTypes")] AgentsMetadata eventTypes, ILogger<Agent>? logger = null)
+public class PBAgent([FromKeyedServices("AgentsMetadata")] AgentsMetadata eventTypes, ILogger<Agent>? logger = null)
     : Agent(eventTypes, logger)
     , IHandle<NewMessageReceived>
     , IHandle<GoodBye>
@@ -31,7 +31,7 @@ public Task Handle(GoodBye item, CancellationToken cancellationToken)
 }
 
 [TopicSubscription("gh-gh-gh")]
-public class GMAgent([FromKeyedServices("EventTypes")] AgentsMetadata eventTypes, ILogger<Agent>? logger = null)
+public class GMAgent([FromKeyedServices("AgentsMetadata")] AgentsMetadata eventTypes, ILogger<Agent>? logger = null)
     : Agent(eventTypes, logger)
     , IHandle<Hello>
 {
diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index d962ae96acb4..09eb1b3fb18e 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -77,12 +77,12 @@ message Subscription {
     }
 }
 
-message AddSubscriptionRequest {
+message SubscriptionRequest {
     string request_id = 1;
     Subscription subscription = 2;
 }
 
-message AddSubscriptionResponse {
+message SubscriptionResponse {
     string request_id = 1;
     bool success = 2;
     optional string error = 3;
@@ -93,7 +93,8 @@ service AgentRpc {
     rpc GetState(AgentId) returns (GetStateResponse);
     rpc SaveState(AgentState) returns (SaveStateResponse);
     rpc RegisterAgent(RegisterAgentTypeRequest) returns (RegisterAgentTypeResponse);
-    rpc AddSubscription(AddSubscriptionRequest) returns (AddSubscriptionResponse);
+    rpc AddSubscription(SubscriptionRequest) returns (SubscriptionResponse);
+    rpc RemoveSubscription(SubscriptionRequest) returns (SubscriptionResponse);
 }
 
 message AgentState {
@@ -124,8 +125,8 @@ message Message {
         io.cloudevents.v1.CloudEvent cloudEvent = 3;
         RegisterAgentTypeRequest registerAgentTypeRequest = 4;
         RegisterAgentTypeResponse registerAgentTypeResponse = 5;
-        AddSubscriptionRequest addSubscriptionRequest = 6;
-        AddSubscriptionResponse addSubscriptionResponse = 7;
+        SubscriptionRequest SubscriptionRequest = 6;
+        SubscriptionResponse SubscriptionResponse = 7;
     }
 }
 
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py
index d2bf41ce0d1f..6b0183080790 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py
@@ -237,7 +237,7 @@ async def _run_read_loop(self) -> None:
                 message = await self._host_connection.recv()  # type: ignore
                 oneofcase = agent_worker_pb2.Message.WhichOneof(message, "message")
                 match oneofcase:
-                    case "registerAgentTypeRequest" | "addSubscriptionRequest":
+                    case "registerAgentTypeRequest" | "SubscriptionRequest":
                         logger.warning(f"Cant handle {oneofcase}, skipping.")
                     case "request":
                         task = asyncio.create_task(self._process_request(message.request))
@@ -263,9 +263,9 @@ async def _run_read_loop(self) -> None:
                         self._background_tasks.add(task)
                         task.add_done_callback(self._raise_on_exception)
                         task.add_done_callback(self._background_tasks.discard)
-                    case "addSubscriptionResponse":
+                    case "SubscriptionResponse":
                         task = asyncio.create_task(
-                            self._process_add_subscription_response(message.addSubscriptionResponse)
+                            self._process_add_subscription_response(message.SubscriptionResponse)
                         )
                         self._background_tasks.add(task)
                         task.add_done_callback(self._raise_on_exception)
@@ -827,7 +827,7 @@ async def add_subscription(self, subscription: Subscription) -> None:
         match subscription:
             case TypeSubscription(topic_type=topic_type, agent_type=agent_type):
                 message = agent_worker_pb2.Message(
-                    addSubscriptionRequest=agent_worker_pb2.AddSubscriptionRequest(
+                    SubscriptionRequest=agent_worker_pb2.SubscriptionRequest(
                         request_id=request_id,
                         subscription=agent_worker_pb2.Subscription(
                             typeSubscription=agent_worker_pb2.TypeSubscription(
@@ -838,7 +838,7 @@ async def add_subscription(self, subscription: Subscription) -> None:
                 )
             case TypePrefixSubscription(topic_type_prefix=topic_type_prefix, agent_type=agent_type):
                 message = agent_worker_pb2.Message(
-                    addSubscriptionRequest=agent_worker_pb2.AddSubscriptionRequest(
+                    SubscriptionRequest=agent_worker_pb2.SubscriptionRequest(
                         request_id=request_id,
                         subscription=agent_worker_pb2.Subscription(
                             typePrefixSubscription=agent_worker_pb2.TypePrefixSubscription(
@@ -862,7 +862,7 @@ async def add_subscription(self, subscription: Subscription) -> None:
         # Wait for the subscription response.
         await future
 
-    async def _process_add_subscription_response(self, response: agent_worker_pb2.AddSubscriptionResponse) -> None:
+    async def _process_add_subscription_response(self, response: agent_worker_pb2.SubscriptionResponse) -> None:
         future = self._pending_requests.pop(response.request_id)
         if response.HasField("error") and response.error != "":
             future.set_exception(RuntimeError(response.error))
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py
index 0bb8ae0a8a20..67a43ef545b4 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py
@@ -127,13 +127,13 @@ async def _receive_messages(
                     self._background_tasks.add(task)
                     task.add_done_callback(self._raise_on_exception)
                     task.add_done_callback(self._background_tasks.discard)
-                case "addSubscriptionRequest":
-                    add_subscription: agent_worker_pb2.AddSubscriptionRequest = message.addSubscriptionRequest
+                case "SubscriptionRequest":
+                    add_subscription: agent_worker_pb2.SubscriptionRequest = message.SubscriptionRequest
                     task = asyncio.create_task(self._process_add_subscription_request(add_subscription, client_id))
                     self._background_tasks.add(task)
                     task.add_done_callback(self._raise_on_exception)
                     task.add_done_callback(self._background_tasks.discard)
-                case "registerAgentTypeResponse" | "addSubscriptionResponse":
+                case "registerAgentTypeResponse" | "SubscriptionResponse":
                     logger.warning(f"Received unexpected message type: {oneofcase}")
                 case None:
                     logger.warning("Received empty message")
@@ -217,7 +217,7 @@ async def _process_register_agent_type_request(
         )
 
     async def _process_add_subscription_request(
-        self, add_subscription_req: agent_worker_pb2.AddSubscriptionRequest, client_id: int
+        self, add_subscription_req: agent_worker_pb2.SubscriptionRequest, client_id: int
     ) -> None:
         oneofcase = add_subscription_req.subscription.WhichOneof("subscription")
         subscription: Subscription | None = None
@@ -254,7 +254,7 @@ async def _process_add_subscription_request(
             # Send a response back to the client.
             await self._send_queues[client_id].put(
                 agent_worker_pb2.Message(
-                    addSubscriptionResponse=agent_worker_pb2.AddSubscriptionResponse(
+                    SubscriptionResponse=agent_worker_pb2.SubscriptionResponse(
                         request_id=add_subscription_req.request_id, success=success, error=error
                     )
                 )
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py
index b4794f1eaba6..76cd7f159b1a 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py
@@ -16,7 +16,7 @@
 from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x61gent_worker.proto\x12\x06\x61gents\x1a\x10\x63loudevent.proto\x1a\x19google/protobuf/any.proto\"\'\n\x07TopicId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0e\n\x06source\x18\x02 \x01(\t\"$\n\x07\x41gentId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\"E\n\x07Payload\x12\x11\n\tdata_type\x18\x01 \x01(\t\x12\x19\n\x11\x64\x61ta_content_type\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\x89\x02\n\nRpcRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12\x1f\n\x06target\x18\x03 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0e\n\x06method\x18\x04 \x01(\t\x12 \n\x07payload\x18\x05 \x01(\x0b\x32\x0f.agents.Payload\x12\x32\n\x08metadata\x18\x06 \x03(\x0b\x32 .agents.RpcRequest.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\xb8\x01\n\x0bRpcResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12 \n\x07payload\x18\x02 \x01(\x0b\x32\x0f.agents.Payload\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x33\n\x08metadata\x18\x04 \x03(\x0b\x32!.agents.RpcResponse.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe4\x01\n\x05\x45vent\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x14\n\x0ctopic_source\x18\x02 \x01(\t\x12$\n\x06source\x18\x03 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12 \n\x07payload\x18\x04 \x01(\x0b\x32\x0f.agents.Payload\x12-\n\x08metadata\x18\x05 \x03(\x0b\x32\x1b.agents.Event.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"<\n\x18RegisterAgentTypeRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\"^\n\x19RegisterAgentTypeResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\":\n\x10TypeSubscription\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"G\n\x16TypePrefixSubscription\x12\x19\n\x11topic_type_prefix\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"\x96\x01\n\x0cSubscription\x12\x34\n\x10typeSubscription\x18\x01 \x01(\x0b\x32\x18.agents.TypeSubscriptionH\x00\x12@\n\x16typePrefixSubscription\x18\x02 \x01(\x0b\x32\x1e.agents.TypePrefixSubscriptionH\x00\x42\x0e\n\x0csubscription\"X\n\x16\x41\x64\x64SubscriptionRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12*\n\x0csubscription\x18\x02 \x01(\x0b\x32\x14.agents.Subscription\"\\\n\x17\x41\x64\x64SubscriptionResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x9d\x01\n\nAgentState\x12!\n\x08\x61gent_id\x18\x01 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0c\n\x04\x65Tag\x18\x02 \x01(\t\x12\x15\n\x0b\x62inary_data\x18\x03 \x01(\x0cH\x00\x12\x13\n\ttext_data\x18\x04 \x01(\tH\x00\x12*\n\nproto_data\x18\x05 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x42\x06\n\x04\x64\x61ta\"j\n\x10GetStateResponse\x12\'\n\x0b\x61gent_state\x18\x01 \x01(\x0b\x32\x12.agents.AgentState\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"B\n\x11SaveStateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xad\x03\n\x07Message\x12%\n\x07request\x18\x01 \x01(\x0b\x32\x12.agents.RpcRequestH\x00\x12\'\n\x08response\x18\x02 \x01(\x0b\x32\x13.agents.RpcResponseH\x00\x12\x33\n\ncloudEvent\x18\x03 \x01(\x0b\x32\x1d.io.cloudevents.v1.CloudEventH\x00\x12\x44\n\x18registerAgentTypeRequest\x18\x04 \x01(\x0b\x32 .agents.RegisterAgentTypeRequestH\x00\x12\x46\n\x19registerAgentTypeResponse\x18\x05 \x01(\x0b\x32!.agents.RegisterAgentTypeResponseH\x00\x12@\n\x16\x61\x64\x64SubscriptionRequest\x18\x06 \x01(\x0b\x32\x1e.agents.AddSubscriptionRequestH\x00\x12\x42\n\x17\x61\x64\x64SubscriptionResponse\x18\x07 \x01(\x0b\x32\x1f.agents.AddSubscriptionResponseH\x00\x42\t\n\x07message2\xb2\x01\n\x08\x41gentRpc\x12\x33\n\x0bOpenChannel\x12\x0f.agents.Message\x1a\x0f.agents.Message(\x01\x30\x01\x12\x35\n\x08GetState\x12\x0f.agents.AgentId\x1a\x18.agents.GetStateResponse\x12:\n\tSaveState\x12\x12.agents.AgentState\x1a\x19.agents.SaveStateResponseB\x1e\xaa\x02\x1bMicrosoft.AutoGen.Contractsb\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x61gent_worker.proto\x12\x06\x61gents\x1a\x10\x63loudevent.proto\x1a\x19google/protobuf/any.proto\"\'\n\x07TopicId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0e\n\x06source\x18\x02 \x01(\t\"$\n\x07\x41gentId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\"E\n\x07Payload\x12\x11\n\tdata_type\x18\x01 \x01(\t\x12\x19\n\x11\x64\x61ta_content_type\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\x89\x02\n\nRpcRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12\x1f\n\x06target\x18\x03 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0e\n\x06method\x18\x04 \x01(\t\x12 \n\x07payload\x18\x05 \x01(\x0b\x32\x0f.agents.Payload\x12\x32\n\x08metadata\x18\x06 \x03(\x0b\x32 .agents.RpcRequest.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\xb8\x01\n\x0bRpcResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12 \n\x07payload\x18\x02 \x01(\x0b\x32\x0f.agents.Payload\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x33\n\x08metadata\x18\x04 \x03(\x0b\x32!.agents.RpcResponse.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe4\x01\n\x05\x45vent\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x14\n\x0ctopic_source\x18\x02 \x01(\t\x12$\n\x06source\x18\x03 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12 \n\x07payload\x18\x04 \x01(\x0b\x32\x0f.agents.Payload\x12-\n\x08metadata\x18\x05 \x03(\x0b\x32\x1b.agents.Event.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\\\n\x18RegisterAgentTypeRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0e\n\x06\x65vents\x18\x03 \x03(\t\x12\x0e\n\x06topics\x18\x04 \x03(\t\"^\n\x19RegisterAgentTypeResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\":\n\x10TypeSubscription\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"G\n\x16TypePrefixSubscription\x12\x19\n\x11topic_type_prefix\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"\x96\x01\n\x0cSubscription\x12\x34\n\x10typeSubscription\x18\x01 \x01(\x0b\x32\x18.agents.TypeSubscriptionH\x00\x12@\n\x16typePrefixSubscription\x18\x02 \x01(\x0b\x32\x1e.agents.TypePrefixSubscriptionH\x00\x42\x0e\n\x0csubscription\"U\n\x13SubscriptionRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12*\n\x0csubscription\x18\x02 \x01(\x0b\x32\x14.agents.Subscription\"Y\n\x14SubscriptionResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x9d\x01\n\nAgentState\x12!\n\x08\x61gent_id\x18\x01 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0c\n\x04\x65Tag\x18\x02 \x01(\t\x12\x15\n\x0b\x62inary_data\x18\x03 \x01(\x0cH\x00\x12\x13\n\ttext_data\x18\x04 \x01(\tH\x00\x12*\n\nproto_data\x18\x05 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x42\x06\n\x04\x64\x61ta\"j\n\x10GetStateResponse\x12\'\n\x0b\x61gent_state\x18\x01 \x01(\x0b\x32\x12.agents.AgentState\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"B\n\x11SaveStateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xa1\x03\n\x07Message\x12%\n\x07request\x18\x01 \x01(\x0b\x32\x12.agents.RpcRequestH\x00\x12\'\n\x08response\x18\x02 \x01(\x0b\x32\x13.agents.RpcResponseH\x00\x12\x33\n\ncloudEvent\x18\x03 \x01(\x0b\x32\x1d.io.cloudevents.v1.CloudEventH\x00\x12\x44\n\x18registerAgentTypeRequest\x18\x04 \x01(\x0b\x32 .agents.RegisterAgentTypeRequestH\x00\x12\x46\n\x19registerAgentTypeResponse\x18\x05 \x01(\x0b\x32!.agents.RegisterAgentTypeResponseH\x00\x12:\n\x13SubscriptionRequest\x18\x06 \x01(\x0b\x32\x1b.agents.SubscriptionRequestH\x00\x12<\n\x14SubscriptionResponse\x18\x07 \x01(\x0b\x32\x1c.agents.SubscriptionResponseH\x00\x42\t\n\x07message2\xa7\x03\n\x08\x41gentRpc\x12\x33\n\x0bOpenChannel\x12\x0f.agents.Message\x1a\x0f.agents.Message(\x01\x30\x01\x12\x35\n\x08GetState\x12\x0f.agents.AgentId\x1a\x18.agents.GetStateResponse\x12:\n\tSaveState\x12\x12.agents.AgentState\x1a\x19.agents.SaveStateResponse\x12T\n\rRegisterAgent\x12 .agents.RegisterAgentTypeRequest\x1a!.agents.RegisterAgentTypeResponse\x12L\n\x0f\x41\x64\x64Subscription\x12\x1b.agents.SubscriptionRequest\x1a\x1c.agents.SubscriptionResponse\x12O\n\x12RemoveSubscription\x12\x1b.agents.SubscriptionRequest\x1a\x1c.agents.SubscriptionResponseB\x1e\xaa\x02\x1bMicrosoft.AutoGen.Contractsb\x06proto3')
 
 _globals = globals()
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -49,27 +49,27 @@
   _globals['_EVENT_METADATAENTRY']._serialized_start=433
   _globals['_EVENT_METADATAENTRY']._serialized_end=480
   _globals['_REGISTERAGENTTYPEREQUEST']._serialized_start=911
-  _globals['_REGISTERAGENTTYPEREQUEST']._serialized_end=971
-  _globals['_REGISTERAGENTTYPERESPONSE']._serialized_start=973
-  _globals['_REGISTERAGENTTYPERESPONSE']._serialized_end=1067
-  _globals['_TYPESUBSCRIPTION']._serialized_start=1069
-  _globals['_TYPESUBSCRIPTION']._serialized_end=1127
-  _globals['_TYPEPREFIXSUBSCRIPTION']._serialized_start=1129
-  _globals['_TYPEPREFIXSUBSCRIPTION']._serialized_end=1200
-  _globals['_SUBSCRIPTION']._serialized_start=1203
-  _globals['_SUBSCRIPTION']._serialized_end=1353
-  _globals['_ADDSUBSCRIPTIONREQUEST']._serialized_start=1355
-  _globals['_ADDSUBSCRIPTIONREQUEST']._serialized_end=1443
-  _globals['_ADDSUBSCRIPTIONRESPONSE']._serialized_start=1445
-  _globals['_ADDSUBSCRIPTIONRESPONSE']._serialized_end=1537
-  _globals['_AGENTSTATE']._serialized_start=1540
-  _globals['_AGENTSTATE']._serialized_end=1697
-  _globals['_GETSTATERESPONSE']._serialized_start=1699
-  _globals['_GETSTATERESPONSE']._serialized_end=1805
-  _globals['_SAVESTATERESPONSE']._serialized_start=1807
-  _globals['_SAVESTATERESPONSE']._serialized_end=1873
-  _globals['_MESSAGE']._serialized_start=1876
-  _globals['_MESSAGE']._serialized_end=2305
-  _globals['_AGENTRPC']._serialized_start=2308
-  _globals['_AGENTRPC']._serialized_end=2486
+  _globals['_REGISTERAGENTTYPEREQUEST']._serialized_end=1003
+  _globals['_REGISTERAGENTTYPERESPONSE']._serialized_start=1005
+  _globals['_REGISTERAGENTTYPERESPONSE']._serialized_end=1099
+  _globals['_TYPESUBSCRIPTION']._serialized_start=1101
+  _globals['_TYPESUBSCRIPTION']._serialized_end=1159
+  _globals['_TYPEPREFIXSUBSCRIPTION']._serialized_start=1161
+  _globals['_TYPEPREFIXSUBSCRIPTION']._serialized_end=1232
+  _globals['_SUBSCRIPTION']._serialized_start=1235
+  _globals['_SUBSCRIPTION']._serialized_end=1385
+  _globals['_SUBSCRIPTIONREQUEST']._serialized_start=1387
+  _globals['_SUBSCRIPTIONREQUEST']._serialized_end=1472
+  _globals['_SUBSCRIPTIONRESPONSE']._serialized_start=1474
+  _globals['_SUBSCRIPTIONRESPONSE']._serialized_end=1563
+  _globals['_AGENTSTATE']._serialized_start=1566
+  _globals['_AGENTSTATE']._serialized_end=1723
+  _globals['_GETSTATERESPONSE']._serialized_start=1725
+  _globals['_GETSTATERESPONSE']._serialized_end=1831
+  _globals['_SAVESTATERESPONSE']._serialized_start=1833
+  _globals['_SAVESTATERESPONSE']._serialized_end=1899
+  _globals['_MESSAGE']._serialized_start=1902
+  _globals['_MESSAGE']._serialized_end=2319
+  _globals['_AGENTRPC']._serialized_start=2322
+  _globals['_AGENTRPC']._serialized_end=2745
 # @@protoc_insertion_point(module_scope)
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi
index 79e384ab948b..ff0ec2e9c801 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi
@@ -220,15 +220,23 @@ class RegisterAgentTypeRequest(google.protobuf.message.Message):
 
     REQUEST_ID_FIELD_NUMBER: builtins.int
     TYPE_FIELD_NUMBER: builtins.int
+    EVENTS_FIELD_NUMBER: builtins.int
+    TOPICS_FIELD_NUMBER: builtins.int
     request_id: builtins.str
     type: builtins.str
+    @property
+    def events(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
+    @property
+    def topics(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[builtins.str]: ...
     def __init__(
         self,
         *,
         request_id: builtins.str = ...,
         type: builtins.str = ...,
+        events: collections.abc.Iterable[builtins.str] | None = ...,
+        topics: collections.abc.Iterable[builtins.str] | None = ...,
     ) -> None: ...
-    def ClearField(self, field_name: typing.Literal["request_id", b"request_id", "type", b"type"]) -> None: ...
+    def ClearField(self, field_name: typing.Literal["events", b"events", "request_id", b"request_id", "topics", b"topics", "type", b"type"]) -> None: ...
 
 global___RegisterAgentTypeRequest = RegisterAgentTypeRequest
 
@@ -314,7 +322,7 @@ class Subscription(google.protobuf.message.Message):
 global___Subscription = Subscription
 
 @typing.final
-class AddSubscriptionRequest(google.protobuf.message.Message):
+class SubscriptionRequest(google.protobuf.message.Message):
     DESCRIPTOR: google.protobuf.descriptor.Descriptor
 
     REQUEST_ID_FIELD_NUMBER: builtins.int
@@ -331,10 +339,10 @@ class AddSubscriptionRequest(google.protobuf.message.Message):
     def HasField(self, field_name: typing.Literal["subscription", b"subscription"]) -> builtins.bool: ...
     def ClearField(self, field_name: typing.Literal["request_id", b"request_id", "subscription", b"subscription"]) -> None: ...
 
-global___AddSubscriptionRequest = AddSubscriptionRequest
+global___SubscriptionRequest = SubscriptionRequest
 
 @typing.final
-class AddSubscriptionResponse(google.protobuf.message.Message):
+class SubscriptionResponse(google.protobuf.message.Message):
     DESCRIPTOR: google.protobuf.descriptor.Descriptor
 
     REQUEST_ID_FIELD_NUMBER: builtins.int
@@ -354,7 +362,7 @@ class AddSubscriptionResponse(google.protobuf.message.Message):
     def ClearField(self, field_name: typing.Literal["_error", b"_error", "error", b"error", "request_id", b"request_id", "success", b"success"]) -> None: ...
     def WhichOneof(self, oneof_group: typing.Literal["_error", b"_error"]) -> typing.Literal["error"] | None: ...
 
-global___AddSubscriptionResponse = AddSubscriptionResponse
+global___SubscriptionResponse = SubscriptionResponse
 
 @typing.final
 class AgentState(google.protobuf.message.Message):
@@ -440,8 +448,8 @@ class Message(google.protobuf.message.Message):
     CLOUDEVENT_FIELD_NUMBER: builtins.int
     REGISTERAGENTTYPEREQUEST_FIELD_NUMBER: builtins.int
     REGISTERAGENTTYPERESPONSE_FIELD_NUMBER: builtins.int
-    ADDSUBSCRIPTIONREQUEST_FIELD_NUMBER: builtins.int
-    ADDSUBSCRIPTIONRESPONSE_FIELD_NUMBER: builtins.int
+    SUBSCRIPTIONREQUEST_FIELD_NUMBER: builtins.int
+    SUBSCRIPTIONRESPONSE_FIELD_NUMBER: builtins.int
     @property
     def request(self) -> global___RpcRequest: ...
     @property
@@ -453,9 +461,9 @@ class Message(google.protobuf.message.Message):
     @property
     def registerAgentTypeResponse(self) -> global___RegisterAgentTypeResponse: ...
     @property
-    def addSubscriptionRequest(self) -> global___AddSubscriptionRequest: ...
+    def SubscriptionRequest(self) -> global___SubscriptionRequest: ...
     @property
-    def addSubscriptionResponse(self) -> global___AddSubscriptionResponse: ...
+    def SubscriptionResponse(self) -> global___SubscriptionResponse: ...
     def __init__(
         self,
         *,
@@ -464,11 +472,11 @@ class Message(google.protobuf.message.Message):
         cloudEvent: cloudevent_pb2.CloudEvent | None = ...,
         registerAgentTypeRequest: global___RegisterAgentTypeRequest | None = ...,
         registerAgentTypeResponse: global___RegisterAgentTypeResponse | None = ...,
-        addSubscriptionRequest: global___AddSubscriptionRequest | None = ...,
-        addSubscriptionResponse: global___AddSubscriptionResponse | None = ...,
+        SubscriptionRequest: global___SubscriptionRequest | None = ...,
+        SubscriptionResponse: global___SubscriptionResponse | None = ...,
     ) -> None: ...
-    def HasField(self, field_name: typing.Literal["addSubscriptionRequest", b"addSubscriptionRequest", "addSubscriptionResponse", b"addSubscriptionResponse", "cloudEvent", b"cloudEvent", "message", b"message", "registerAgentTypeRequest", b"registerAgentTypeRequest", "registerAgentTypeResponse", b"registerAgentTypeResponse", "request", b"request", "response", b"response"]) -> builtins.bool: ...
-    def ClearField(self, field_name: typing.Literal["addSubscriptionRequest", b"addSubscriptionRequest", "addSubscriptionResponse", b"addSubscriptionResponse", "cloudEvent", b"cloudEvent", "message", b"message", "registerAgentTypeRequest", b"registerAgentTypeRequest", "registerAgentTypeResponse", b"registerAgentTypeResponse", "request", b"request", "response", b"response"]) -> None: ...
-    def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["request", "response", "cloudEvent", "registerAgentTypeRequest", "registerAgentTypeResponse", "addSubscriptionRequest", "addSubscriptionResponse"] | None: ...
+    def HasField(self, field_name: typing.Literal["SubscriptionRequest", b"SubscriptionRequest", "SubscriptionResponse", b"SubscriptionResponse", "cloudEvent", b"cloudEvent", "message", b"message", "registerAgentTypeRequest", b"registerAgentTypeRequest", "registerAgentTypeResponse", b"registerAgentTypeResponse", "request", b"request", "response", b"response"]) -> builtins.bool: ...
+    def ClearField(self, field_name: typing.Literal["SubscriptionRequest", b"SubscriptionRequest", "SubscriptionResponse", b"SubscriptionResponse", "cloudEvent", b"cloudEvent", "message", b"message", "registerAgentTypeRequest", b"registerAgentTypeRequest", "registerAgentTypeResponse", b"registerAgentTypeResponse", "request", b"request", "response", b"response"]) -> None: ...
+    def WhichOneof(self, oneof_group: typing.Literal["message", b"message"]) -> typing.Literal["request", "response", "cloudEvent", "registerAgentTypeRequest", "registerAgentTypeResponse", "SubscriptionRequest", "SubscriptionResponse"] | None: ...
 
 global___Message = Message
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py
index fc27021587f6..c363d9968034 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py
@@ -29,6 +29,21 @@ def __init__(self, channel):
                 request_serializer=agent__worker__pb2.AgentState.SerializeToString,
                 response_deserializer=agent__worker__pb2.SaveStateResponse.FromString,
                 )
+        self.RegisterAgent = channel.unary_unary(
+                '/agents.AgentRpc/RegisterAgent',
+                request_serializer=agent__worker__pb2.RegisterAgentTypeRequest.SerializeToString,
+                response_deserializer=agent__worker__pb2.RegisterAgentTypeResponse.FromString,
+                )
+        self.AddSubscription = channel.unary_unary(
+                '/agents.AgentRpc/AddSubscription',
+                request_serializer=agent__worker__pb2.SubscriptionRequest.SerializeToString,
+                response_deserializer=agent__worker__pb2.SubscriptionResponse.FromString,
+                )
+        self.RemoveSubscription = channel.unary_unary(
+                '/agents.AgentRpc/RemoveSubscription',
+                request_serializer=agent__worker__pb2.SubscriptionRequest.SerializeToString,
+                response_deserializer=agent__worker__pb2.SubscriptionResponse.FromString,
+                )
 
 
 class AgentRpcServicer(object):
@@ -52,6 +67,24 @@ def SaveState(self, request, context):
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
+    def RegisterAgent(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def AddSubscription(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def RemoveSubscription(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
 
 def add_AgentRpcServicer_to_server(servicer, server):
     rpc_method_handlers = {
@@ -70,6 +103,21 @@ def add_AgentRpcServicer_to_server(servicer, server):
                     request_deserializer=agent__worker__pb2.AgentState.FromString,
                     response_serializer=agent__worker__pb2.SaveStateResponse.SerializeToString,
             ),
+            'RegisterAgent': grpc.unary_unary_rpc_method_handler(
+                    servicer.RegisterAgent,
+                    request_deserializer=agent__worker__pb2.RegisterAgentTypeRequest.FromString,
+                    response_serializer=agent__worker__pb2.RegisterAgentTypeResponse.SerializeToString,
+            ),
+            'AddSubscription': grpc.unary_unary_rpc_method_handler(
+                    servicer.AddSubscription,
+                    request_deserializer=agent__worker__pb2.SubscriptionRequest.FromString,
+                    response_serializer=agent__worker__pb2.SubscriptionResponse.SerializeToString,
+            ),
+            'RemoveSubscription': grpc.unary_unary_rpc_method_handler(
+                    servicer.RemoveSubscription,
+                    request_deserializer=agent__worker__pb2.SubscriptionRequest.FromString,
+                    response_serializer=agent__worker__pb2.SubscriptionResponse.SerializeToString,
+            ),
     }
     generic_handler = grpc.method_handlers_generic_handler(
             'agents.AgentRpc', rpc_method_handlers)
@@ -130,3 +178,54 @@ def SaveState(request,
             agent__worker__pb2.SaveStateResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def RegisterAgent(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/RegisterAgent',
+            agent__worker__pb2.RegisterAgentTypeRequest.SerializeToString,
+            agent__worker__pb2.RegisterAgentTypeResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def AddSubscription(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/AddSubscription',
+            agent__worker__pb2.SubscriptionRequest.SerializeToString,
+            agent__worker__pb2.SubscriptionResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def RemoveSubscription(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/RemoveSubscription',
+            agent__worker__pb2.SubscriptionRequest.SerializeToString,
+            agent__worker__pb2.SubscriptionResponse.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi
index bf6bc1ba2d64..94539461f70c 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi
@@ -34,6 +34,21 @@ class AgentRpcStub:
         agent_worker_pb2.SaveStateResponse,
     ]
 
+    RegisterAgent: grpc.UnaryUnaryMultiCallable[
+        agent_worker_pb2.RegisterAgentTypeRequest,
+        agent_worker_pb2.RegisterAgentTypeResponse,
+    ]
+
+    AddSubscription: grpc.UnaryUnaryMultiCallable[
+        agent_worker_pb2.SubscriptionRequest,
+        agent_worker_pb2.SubscriptionResponse,
+    ]
+
+    RemoveSubscription: grpc.UnaryUnaryMultiCallable[
+        agent_worker_pb2.SubscriptionRequest,
+        agent_worker_pb2.SubscriptionResponse,
+    ]
+
 class AgentRpcAsyncStub:
     OpenChannel: grpc.aio.StreamStreamMultiCallable[
         agent_worker_pb2.Message,
@@ -50,6 +65,21 @@ class AgentRpcAsyncStub:
         agent_worker_pb2.SaveStateResponse,
     ]
 
+    RegisterAgent: grpc.aio.UnaryUnaryMultiCallable[
+        agent_worker_pb2.RegisterAgentTypeRequest,
+        agent_worker_pb2.RegisterAgentTypeResponse,
+    ]
+
+    AddSubscription: grpc.aio.UnaryUnaryMultiCallable[
+        agent_worker_pb2.SubscriptionRequest,
+        agent_worker_pb2.SubscriptionResponse,
+    ]
+
+    RemoveSubscription: grpc.aio.UnaryUnaryMultiCallable[
+        agent_worker_pb2.SubscriptionRequest,
+        agent_worker_pb2.SubscriptionResponse,
+    ]
+
 class AgentRpcServicer(metaclass=abc.ABCMeta):
     @abc.abstractmethod
     def OpenChannel(
@@ -72,4 +102,25 @@ class AgentRpcServicer(metaclass=abc.ABCMeta):
         context: _ServicerContext,
     ) -> typing.Union[agent_worker_pb2.SaveStateResponse, collections.abc.Awaitable[agent_worker_pb2.SaveStateResponse]]: ...
 
+    @abc.abstractmethod
+    def RegisterAgent(
+        self,
+        request: agent_worker_pb2.RegisterAgentTypeRequest,
+        context: _ServicerContext,
+    ) -> typing.Union[agent_worker_pb2.RegisterAgentTypeResponse, collections.abc.Awaitable[agent_worker_pb2.RegisterAgentTypeResponse]]: ...
+
+    @abc.abstractmethod
+    def AddSubscription(
+        self,
+        request: agent_worker_pb2.SubscriptionRequest,
+        context: _ServicerContext,
+    ) -> typing.Union[agent_worker_pb2.SubscriptionResponse, collections.abc.Awaitable[agent_worker_pb2.SubscriptionResponse]]: ...
+
+    @abc.abstractmethod
+    def RemoveSubscription(
+        self,
+        request: agent_worker_pb2.SubscriptionRequest,
+        context: _ServicerContext,
+    ) -> typing.Union[agent_worker_pb2.SubscriptionResponse, collections.abc.Awaitable[agent_worker_pb2.SubscriptionResponse]]: ...
+
 def add_AgentRpcServicer_to_server(servicer: AgentRpcServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ...

From 823019d7b3d3617931ed83b67403793040cdd682 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sat, 21 Dec 2024 21:10:35 -0800
Subject: [PATCH 016/110] start mustnt wait

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 50a29203d4c7..da3dfa6388fa 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -49,7 +49,7 @@ protected Agent(
     public static void Initialize(IAgentWorker worker, Agent agent)
     {
         agent.Worker = worker;
-        agent.Start().Wait();
+        agent.Start();
         agent.AddImplicitSubscriptionsAsync().AsTask().Wait();
     }
 

From b501d25aa40a97a9463bf6a31657b96afcd4c2d9 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sat, 21 Dec 2024 22:01:05 -0800
Subject: [PATCH 017/110] add unsubscribe

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 40 ++++++++++++-------
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs | 20 ++++++++++
 .../AgentTests.cs                             | 28 ++++++++++++-
 3 files changed, 71 insertions(+), 17 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index da3dfa6388fa..9385d9fda223 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -76,7 +76,7 @@ private async ValueTask AddImplicitSubscriptionsAsync()
                 }
             };
             // explicitly wait for this to complete
-            await Worker.SendMessageAsync(new Message { SubscriptionRequest = subscriptionRequest }).ConfigureAwait(true);
+            Worker.SubscribeAsync(subscriptionRequest).AsTask().Wait();
         }
 
         // using reflection, find all methods that Handle<T> and subscribe to the topic T
@@ -89,7 +89,7 @@ private async ValueTask AddImplicitSubscriptionsAsync()
             {
                 foreach (var topic in topics)
                 {
-                    Subscribe(topic);
+                    await SubscribeAsync(topic).ConfigureAwait(true);
                 }
             }
         }
@@ -177,26 +177,36 @@ public async ValueTask<List<Subscription>> GetSubscriptionsAsync()
     {
         return await Worker.GetSubscriptionsAsync(GetType()).ConfigureAwait(false);
     }
-    public List<string> Subscribe(string topic)
+    public async ValueTask<SubscriptionResponse> SubscribeAsync(string topic)
     {
-        Message message = new()
+        return await UpdateSubscriptionAsync(topic, true).ConfigureAwait(true);
+    }
+    public async ValueTask<SubscriptionResponse> UnsubscribeAsync(string topic)
+    {
+        return await UpdateSubscriptionAsync(topic, false).ConfigureAwait(true);
+    }
+    private async ValueTask<SubscriptionResponse> UpdateSubscriptionAsync(string topic, bool subscribe)
+    {
+        SubscriptionRequest subscriptionRequest = new()
         {
-            SubscriptionRequest = new()
+            RequestId = Guid.NewGuid().ToString(),
+            Subscription = new Subscription
             {
-                RequestId = Guid.NewGuid().ToString(),
-                Subscription = new Subscription
+                TypeSubscription = new TypeSubscription
                 {
-                    TypeSubscription = new TypeSubscription
-                    {
-                        TopicType = topic,
-                        AgentType = this.AgentId.Key
-                    }
+                    TopicType = topic,
+                    AgentType = this.AgentId.Type
                 }
             }
         };
-        Worker.SendMessageAsync(message).AsTask().Wait();
-
-        return new List<string> { topic };
+        var subscriptionResponse = subscribe
+            ? await Worker.SubscribeAsync(subscriptionRequest).ConfigureAwait(true)
+            : await Worker.UnsubscribeAsync(subscriptionRequest).ConfigureAwait(true);
+        if (!subscriptionResponse.Success)
+        {
+            _logger.LogError($"{GetType}{AgentId.Key}: Failed to unsubscribe from topic {topic}");
+        }
+        return subscriptionResponse;
     }
     public async Task StoreAsync(AgentState state, CancellationToken cancellationToken = default)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 8de12f77bb4a..8697f99c9701 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -148,6 +148,26 @@ public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest
         };
         return response;
     }
+    public async ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    {
+        var topic = request.Subscription.TypeSubscription.TopicType;
+        var agentType = request.Subscription.TypeSubscription.AgentType;
+        if (_subscriptionsByAgentType.TryGetValue(agentType, out var subscriptions))
+        {
+            subscriptions.Remove(request.Subscription);
+        }
+        if (_subscriptionsByTopic.TryGetValue(topic, out var agentTypes))
+        {
+            agentTypes.Remove(agentType);
+        }
+        var response = new SubscriptionResponse
+        {
+            RequestId = request.RequestId,
+            Error = "",
+            Success = true
+        };
+        return response;
+    }
 
     public async Task StartAsync(CancellationToken cancellationToken)
     {
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 2fb8a3a8e638..f4403f5278e5 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -29,10 +29,15 @@ public class AgentTests(InMemoryAgentRuntimeFixture fixture)
     /// </summary>
     /// <returns>void</returns>
     [Fact]
-    public void Agent_ShouldThrowException_WhenNotInitialized()
+    public async Task Agent_ShouldThrowException_WhenNotInitialized()
     {
         var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
-        Assert.Throws<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(() => { agent.Subscribe("TestEvent"); });
+        await Assert.ThrowsAsync<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(
+            async () =>
+            {
+                await agent.SubscribeAsync("TestEvent");
+            }
+        );
     }
 
     /// <summary>
@@ -49,6 +54,25 @@ public async Task Agent_ShouldInitializeCorrectly()
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
     }
+    /// <summary>
+    /// Test SubscribeAsync method
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        Assert.Equal(2, subscriptions.Count);
+        await agent.SubscribeAsync("TestEvent");
+        subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        Assert.Equal(3, subscriptions.Count);
+        await agent.UnsubscribeAsync("TestEvent");
+        subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        Assert.Equal(2, subscriptions.Count);
+    }
 
     [Fact]
     public async Task ItInvokeRightHandlerTestAsync()

From 83f5fc0df87fc8a8446b7a0afe92622fb96db787 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 22 Dec 2024 10:42:21 -0800
Subject: [PATCH 018/110] adding tests for agentstate

---
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs |  4 ---
 .../AgentTests.cs                             | 26 +++++++++++++++++++
 2 files changed, 26 insertions(+), 4 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 8697f99c9701..2bdeb4e22af8 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -253,8 +253,4 @@ public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
         }
         return new ValueTask<List<Subscription>>([]);
     }
-    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
-    {
-        throw new NotImplementedException();
-    }
 }
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index f4403f5278e5..30c0bf22c844 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -3,6 +3,7 @@
 
 using System.Collections.Concurrent;
 using System.Diagnostics;
+using System.Text.Json;
 using FluentAssertions;
 using Google.Protobuf.Reflection;
 using Microsoft.AspNetCore.Builder;
@@ -74,6 +75,31 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
         Assert.Equal(2, subscriptions.Count);
     }
 
+    /// <summary>
+    /// Test StoreAsync and ReadAsync methods
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task StoreAsync_and_ReadAsyncTest()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        Dictionary<string, string> state = new()
+        {
+            { "testdata", "Active" }
+        };
+        await agent.StoreAsync(new AgentState
+            {
+                AgentId = agent.AgentId,
+                TextData = JsonSerializer.Serialize(state)
+            }).ConfigureAwait(true);
+        var readState = await agent.ReadAsync<AgentState>(agent.AgentId).ConfigureAwait(true);
+        var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
+        read.TryGetValue("testdata", out var value);
+        Assert.Equal("Active", value);
+    }
+
     [Fact]
     public async Task ItInvokeRightHandlerTestAsync()
     {

From acaf3d33ddaa87bcdef4859d239f7730908c31ef Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 22 Dec 2024 10:59:38 -0800
Subject: [PATCH 019/110] publish and receive test

---
 .../AgentTests.cs                             | 30 +++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 30c0bf22c844..ff162aab6711 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -100,6 +100,36 @@ await agent.StoreAsync(new AgentState
         Assert.Equal("Active", value);
     }
 
+    /// <summary>
+    /// Test PublishMessageAsync method and ReceiveMessage method
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task PublishMessageAsync_and_ReceiveMessageTest()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        await agent.SubscribeAsync("TestEvent").ConfigureAwait(true);
+        var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        var found = false;
+        foreach (var subscription in subscriptions)
+        {
+            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            {
+                found = true;
+            }
+        }
+        Assert.True(found);
+        await agent.PublishMessageAsync(new TextMessage()
+        {
+            Source = "TestEvent",
+            TextMessage_ = "buffer"
+        }).ConfigureAwait(true);
+        await Task.Delay(100);
+        Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
+    }
+
     [Fact]
     public async Task ItInvokeRightHandlerTestAsync()
     {

From 1d6e4437b24e01ae1da8ea4f3f555c6a5587af92 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 08:53:55 -0800
Subject: [PATCH 020/110] Improving the subscription tests timing

---
 .../AgentTests.cs                             | 111 +++++++++++++++---
 1 file changed, 92 insertions(+), 19 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index ff162aab6711..8e5cf309e2ea 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -48,12 +48,11 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     [Fact]
     public async Task Agent_ShouldInitializeCorrectly()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
-        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
-        Agent.Initialize(worker, agent);
-        Assert.Equal("AgentWorker", agent.Worker.GetType().Name);
+        var (worker, agent) = _fixture.Start();
+        Assert.Equal("AgentWorker", worker.GetType().Name);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
+        _fixture.Stop();
     }
     /// <summary>
     /// Test SubscribeAsync method
@@ -62,17 +61,32 @@ public async Task Agent_ShouldInitializeCorrectly()
     [Fact]
     public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
-        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
-        Agent.Initialize(worker, agent);
-        var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
-        Assert.Equal(2, subscriptions.Count);
+        var (_, agent) = _fixture.Start();
         await agent.SubscribeAsync("TestEvent");
+        await Task.Delay(100);
+        var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        var found = false;
+        foreach (var subscription in subscriptions)
+        {
+            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            {
+                found = true;
+            }
+        }
+        Assert.True(found);
+        await agent.UnsubscribeAsync("TestEvent").ConfigureAwait(true);
+        await Task.Delay(500);
         subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
-        Assert.Equal(3, subscriptions.Count);
-        await agent.UnsubscribeAsync("TestEvent");
-        subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
-        Assert.Equal(2, subscriptions.Count);
+        found = false;
+        foreach (var subscription in subscriptions)
+        {
+            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            {
+                found = true;
+            }
+        }
+        Assert.False(found);
+        _fixture.Stop();
     }
 
     /// <summary>
@@ -82,9 +96,7 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
     [Fact]
     public async Task StoreAsync_and_ReadAsyncTest()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
-        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
-        Agent.Initialize(worker, agent);
+        var (_, agent) = _fixture.Start();
         Dictionary<string, string> state = new()
         {
             { "testdata", "Active" }
@@ -98,6 +110,7 @@ await agent.StoreAsync(new AgentState
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);
         Assert.Equal("Active", value);
+        _fixture.Stop();
     }
 
     /// <summary>
@@ -107,9 +120,7 @@ await agent.StoreAsync(new AgentState
     [Fact]
     public async Task PublishMessageAsync_and_ReceiveMessageTest()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
-        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
-        Agent.Initialize(worker, agent);
+        var (_, agent) = _fixture.Start();
         await agent.SubscribeAsync("TestEvent").ConfigureAwait(true);
         var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
         var found = false;
@@ -128,6 +139,7 @@ await agent.PublishMessageAsync(new TextMessage()
         }).ConfigureAwait(true);
         await Task.Delay(100);
         Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
+        _fixture.Stop();
     }
 
     [Fact]
@@ -163,6 +175,41 @@ await client.PublishMessageAsync(new TextMessage()
         TestAgent.ReceivedMessages[nameof(ItDelegateMessageToTestAgentAsync)].Should().NotBeNull();
     }
 
+    /// <summary>
+    /// GetAppHost - provides an app host used for one test vs the fixture which is shared. 
+    /// </summary>
+    /// <returns>WebApplication</returns>
+    internal static WebApplication GetAppHost()
+    {
+        var builder = WebApplication.CreateBuilder();
+        builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
+        builder.AddAgentWorker()
+            .AddAgent<TestAgent>(nameof(TestAgent));
+        Host = builder.Build();
+        Host.StartAsync().Wait();
+        return Host;
+    }
+    /// <summary>
+    /// Start - starts the agent
+    /// </summary>
+    /// <returns>IAgentWorker, TestAgent</returns>
+    internal (IAgentWorker, TestAgent) Start()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(GetAppHost().Services);
+        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        return (worker, agent);
+    }
+    /// <summary>
+    /// Stop - stops the agent
+    /// </summary>
+    /// <param name="Host">WebApplication</param>
+    /// <returns>void</returns>
+    internal static void Stop(WebApplication Host)
+    {
+        Host.StopAsync().Wait();
+    }
+
     /// <summary>
     /// The test agent is a simple agent that is used for testing purposes.
     /// </summary>
@@ -195,6 +242,13 @@ public Task Handle(int item)
     }
 }
 
+/// <summary>
+/// InMemoryAgentRuntimeFixture - provides a fixture for the agent runtime.
+/// </summary>
+/// <remarks>
+/// This fixture is used to provide a runtime for the agent tests.
+/// However, it is shared between tests. So operations from one test can affect another.
+/// </remarks>
 public sealed class InMemoryAgentRuntimeFixture : IDisposable
 {
     public InMemoryAgentRuntimeFixture()
@@ -213,6 +267,25 @@ void IDisposable.Dispose()
         AppHost.StopAsync().Wait();
         AppHost.Dispose();
     }
+        /// <summary>
+    /// Start - starts the agent
+    /// </summary>
+    /// <returns>IAgentWorker, TestAgent</returns>
+    public (IAgentWorker, TestAgent) Start()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(AppHost.Services);
+        var worker = AppHost.Services.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        return (worker, agent);
+    }
+    /// <summary>
+    /// Stop - stops the agent
+    /// </summary>
+    /// <returns>void</returns>
+    public void Stop()
+    {
+        AppHost.StopAsync().Wait();
+    }
 }
 
 [CollectionDefinition(Name)]

From 7d4308fd6873e1e734136d574b662ff110c70ad0 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 11:29:59 -0800
Subject: [PATCH 021/110] tests pass now

---
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs | 10 ++++++++--
 .../AgentTests.cs                             | 20 +++++++++----------
 2 files changed, 17 insertions(+), 13 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index 2bdeb4e22af8..aaf6c795d14d 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -154,11 +154,17 @@ public async ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionReques
         var agentType = request.Subscription.TypeSubscription.AgentType;
         if (_subscriptionsByAgentType.TryGetValue(agentType, out var subscriptions))
         {
-            subscriptions.Remove(request.Subscription);
+            while (subscriptions.Remove(request.Subscription))
+            {
+                //ensures all instances are removed    
+            }
         }
         if (_subscriptionsByTopic.TryGetValue(topic, out var agentTypes))
         {
-            agentTypes.Remove(agentType);
+            while (agentTypes.Remove(agentType))
+            {
+                //ensures all instances are removed
+            }
         }
         var response = new SubscriptionResponse
         {
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 8e5cf309e2ea..c349a32cb460 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -193,12 +193,13 @@ internal static WebApplication GetAppHost()
     /// Start - starts the agent
     /// </summary>
     /// <returns>IAgentWorker, TestAgent</returns>
-    internal (IAgentWorker, TestAgent) Start()
+    internal (WebApplication, IAgentWorker, TestAgent) Start()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(GetAppHost().Services);
+        var host = GetAppHost();
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(host.Services);
         var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
         Agent.Initialize(worker, agent);
-        return (worker, agent);
+        return (host, worker, agent);
     }
     /// <summary>
     /// Stop - stops the agent
@@ -208,6 +209,7 @@ internal static WebApplication GetAppHost()
     internal static void Stop(WebApplication Host)
     {
         Host.StopAsync().Wait();
+        Host.DisposeAsync().AsTask().Wait();
     }
 
     /// <summary>
@@ -249,7 +251,7 @@ public Task Handle(int item)
 /// This fixture is used to provide a runtime for the agent tests.
 /// However, it is shared between tests. So operations from one test can affect another.
 /// </remarks>
-public sealed class InMemoryAgentRuntimeFixture : IDisposable
+public sealed class InMemoryAgentRuntimeFixture
 {
     public InMemoryAgentRuntimeFixture()
     {
@@ -262,12 +264,7 @@ public InMemoryAgentRuntimeFixture()
     }
     public IHost AppHost { get; }
 
-    void IDisposable.Dispose()
-    {
-        AppHost.StopAsync().Wait();
-        AppHost.Dispose();
-    }
-        /// <summary>
+    /// <summary>
     /// Start - starts the agent
     /// </summary>
     /// <returns>IAgentWorker, TestAgent</returns>
@@ -284,7 +281,8 @@ void IDisposable.Dispose()
     /// <returns>void</returns>
     public void Stop()
     {
-        AppHost.StopAsync().Wait();
+        IHostApplicationLifetime hostApplicationLifetime = AppHost.Services.GetRequiredService<IHostApplicationLifetime>();
+        hostApplicationLifetime.StopApplication();
     }
 }
 

From 2e1d24f90b766a60db8d253654d206f62f5c7eb5 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 11:31:38 -0800
Subject: [PATCH 022/110] rename some wierd methods

---
 dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index c349a32cb460..0eb5bb7c1a0b 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -143,7 +143,7 @@ await agent.PublishMessageAsync(new TextMessage()
     }
 
     [Fact]
-    public async Task ItInvokeRightHandlerTestAsync()
+    public async Task InvokeCorrectHandler()
     {
         var agent = new TestAgent(new AgentsMetadata(TypeRegistry.Empty, new Dictionary<string, Type>(), new Dictionary<Type, HashSet<string>>(), new Dictionary<Type, HashSet<string>>()), new Logger<Agent>(new LoggerFactory()));
 
@@ -156,23 +156,23 @@ public async Task ItInvokeRightHandlerTestAsync()
     }
 
     [Fact]
-    public async Task ItDelegateMessageToTestAgentAsync()
+    public async Task DelegateMessageToTestAgentAsync()
     {
         var client = _fixture.AppHost.Services.GetRequiredService<Client>();
         await client.PublishMessageAsync(new TextMessage()
         {
-            Source = nameof(ItDelegateMessageToTestAgentAsync),
+            Source = nameof(DelegateMessageToTestAgentAsync),
             TextMessage_ = "buffer"
         }, token: CancellationToken.None);
 
         // wait for 10 seconds
         var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
-        while (!TestAgent.ReceivedMessages.ContainsKey(nameof(ItDelegateMessageToTestAgentAsync)) && !cts.Token.IsCancellationRequested)
+        while (!TestAgent.ReceivedMessages.ContainsKey(nameof(DelegateMessageToTestAgentAsync)) && !cts.Token.IsCancellationRequested)
         {
             await Task.Delay(100);
         }
 
-        TestAgent.ReceivedMessages[nameof(ItDelegateMessageToTestAgentAsync)].Should().NotBeNull();
+        TestAgent.ReceivedMessages[nameof(DelegateMessageToTestAgentAsync)].Should().NotBeNull();
     }
 
     /// <summary>

From b69bbb56e0c2a5f958828f9a2ed47992600b819b Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 12:07:09 -0800
Subject: [PATCH 023/110] remove unused.

---
 .../AgentTests.cs                             | 37 -------------------
 1 file changed, 37 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 0eb5bb7c1a0b..02e927b072e9 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -175,43 +175,6 @@ await client.PublishMessageAsync(new TextMessage()
         TestAgent.ReceivedMessages[nameof(DelegateMessageToTestAgentAsync)].Should().NotBeNull();
     }
 
-    /// <summary>
-    /// GetAppHost - provides an app host used for one test vs the fixture which is shared. 
-    /// </summary>
-    /// <returns>WebApplication</returns>
-    internal static WebApplication GetAppHost()
-    {
-        var builder = WebApplication.CreateBuilder();
-        builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
-        builder.AddAgentWorker()
-            .AddAgent<TestAgent>(nameof(TestAgent));
-        Host = builder.Build();
-        Host.StartAsync().Wait();
-        return Host;
-    }
-    /// <summary>
-    /// Start - starts the agent
-    /// </summary>
-    /// <returns>IAgentWorker, TestAgent</returns>
-    internal (WebApplication, IAgentWorker, TestAgent) Start()
-    {
-        var host = GetAppHost();
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(host.Services);
-        var worker = _serviceProvider.GetRequiredService<IAgentWorker>();
-        Agent.Initialize(worker, agent);
-        return (host, worker, agent);
-    }
-    /// <summary>
-    /// Stop - stops the agent
-    /// </summary>
-    /// <param name="Host">WebApplication</param>
-    /// <returns>void</returns>
-    internal static void Stop(WebApplication Host)
-    {
-        Host.StopAsync().Wait();
-        Host.DisposeAsync().AsTask().Wait();
-    }
-
     /// <summary>
     /// The test agent is a simple agent that is used for testing purposes.
     /// </summary>

From 1d583230f48d3477336e6da1241d676cd03b0fdc Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 12:11:53 -0800
Subject: [PATCH 024/110] adding test project for grpc core

---
 dotnet/AutoGen.sln                            |   7 +
 .../AgentGrpcTests.cs                         | 254 ++++++++++++++++++
 .../Microsoft.AutoGen.Core.Grpc.Tests.csproj  |  16 ++
 3 files changed, 277 insertions(+)
 create mode 100644 dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
 create mode 100644 dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index 116411d25489..76a759e37692 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -142,6 +142,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Test
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.ServiceDefaults", "samples\dev-team\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj", "{599E1971-1DA9-453F-A7A8-42510BBC95C2}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Grpc.Tests", "test\Microsoft.AutoGen.Core.Grpc.Tests\Microsoft.AutoGen.Core.Grpc.Tests.csproj", "{33A28A4B-123B-4416-9631-0F759B8D6172}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -372,6 +374,10 @@ Global
 		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{599E1971-1DA9-453F-A7A8-42510BBC95C2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{33A28A4B-123B-4416-9631-0F759B8D6172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{33A28A4B-123B-4416-9631-0F759B8D6172}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{33A28A4B-123B-4416-9631-0F759B8D6172}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{33A28A4B-123B-4416-9631-0F759B8D6172}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -437,6 +443,7 @@ Global
 		{14F90F79-580E-454D-BA7A-ED6D9723020D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{599E1971-1DA9-453F-A7A8-42510BBC95C2} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
+		{33A28A4B-123B-4416-9631-0F759B8D6172} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
new file mode 100644
index 000000000000..275b82e745e2
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -0,0 +1,254 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// AgentGrpcTests.cs
+
+using System.Collections.Concurrent;
+using System.Text.Json;
+using FluentAssertions;
+using Google.Protobuf.Reflection;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AutoGen.Contracts;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using Xunit;
+using static Microsoft.AutoGen.Core.Grpc.Tests.AgentGrpcTests;
+
+namespace Microsoft.AutoGen.Core.Grpc.Tests;
+
+[Collection(GrpcClusterFixtureCollection.Name)]
+public class AgentGrpcTests(GrpcRuntimeFixture fixture)
+{
+    private readonly IServiceProvider _serviceProvider = fixture.AppHost.Services;
+    private readonly GrpcRuntimeFixture _fixture = fixture;
+    // need a variable to store the runtime instance
+    public static WebApplication? Host { get; private set; }
+
+    /// <summary>
+    /// Verify that if the agent is not initialized via AgentWorker, it should throw the correct exception.
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task Agent_ShouldThrowException_WhenNotInitialized()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        await Assert.ThrowsAsync<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(
+            async () =>
+            {
+                await agent.SubscribeAsync("TestEvent");
+            }
+        );
+    }
+
+    /// <summary>
+    /// validate that the agent is initialized correctly with implicit subs
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task Agent_ShouldInitializeCorrectly()
+    {
+        var (worker, agent) = _fixture.Start();
+        Assert.Equal("AgentWorker", worker.GetType().Name);
+        var subscriptions = await agent.GetSubscriptionsAsync();
+        Assert.Equal(2, subscriptions.Count);
+        _fixture.Stop();
+    }
+    /// <summary>
+    /// Test SubscribeAsync method
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
+    {
+        var (_, agent) = _fixture.Start();
+        await agent.SubscribeAsync("TestEvent");
+        await Task.Delay(100);
+        var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        var found = false;
+        foreach (var subscription in subscriptions)
+        {
+            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            {
+                found = true;
+            }
+        }
+        Assert.True(found);
+        await agent.UnsubscribeAsync("TestEvent").ConfigureAwait(true);
+        await Task.Delay(500);
+        subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        found = false;
+        foreach (var subscription in subscriptions)
+        {
+            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            {
+                found = true;
+            }
+        }
+        Assert.False(found);
+        _fixture.Stop();
+    }
+
+    /// <summary>
+    /// Test StoreAsync and ReadAsync methods
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task StoreAsync_and_ReadAsyncTest()
+    {
+        var (_, agent) = _fixture.Start();
+        Dictionary<string, string> state = new()
+        {
+            { "testdata", "Active" }
+        };
+        await agent.StoreAsync(new AgentState
+            {
+                AgentId = agent.AgentId,
+                TextData = JsonSerializer.Serialize(state)
+            }).ConfigureAwait(true);
+        var readState = await agent.ReadAsync<AgentState>(agent.AgentId).ConfigureAwait(true);
+        var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
+        read.TryGetValue("testdata", out var value);
+        Assert.Equal("Active", value);
+        _fixture.Stop();
+    }
+
+    /// <summary>
+    /// Test PublishMessageAsync method and ReceiveMessage method
+    /// </summary>
+    /// <returns>void</returns>
+    [Fact]
+    public async Task PublishMessageAsync_and_ReceiveMessageTest()
+    {
+        var (_, agent) = _fixture.Start();
+        await agent.SubscribeAsync("TestEvent").ConfigureAwait(true);
+        var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
+        var found = false;
+        foreach (var subscription in subscriptions)
+        {
+            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            {
+                found = true;
+            }
+        }
+        Assert.True(found);
+        await agent.PublishMessageAsync(new TextMessage()
+        {
+            Source = "TestEvent",
+            TextMessage_ = "buffer"
+        }).ConfigureAwait(true);
+        await Task.Delay(100);
+        Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
+        _fixture.Stop();
+    }
+
+    [Fact]
+    public async Task InvokeCorrectHandler()
+    {
+        var agent = new TestAgent(new AgentsMetadata(TypeRegistry.Empty, new Dictionary<string, Type>(), new Dictionary<Type, HashSet<string>>(), new Dictionary<Type, HashSet<string>>()), new Logger<Agent>(new LoggerFactory()));
+
+        await agent.HandleObjectAsync("hello world");
+        await agent.HandleObjectAsync(42);
+
+        agent.ReceivedItems.Should().HaveCount(2);
+        agent.ReceivedItems[0].Should().Be("hello world");
+        agent.ReceivedItems[1].Should().Be(42);
+    }
+
+    [Fact]
+    public async Task DelegateMessageToTestAgentAsync()
+    {
+        var client = _fixture.AppHost.Services.GetRequiredService<Client>();
+        await client.PublishMessageAsync(new TextMessage()
+        {
+            Source = nameof(DelegateMessageToTestAgentAsync),
+            TextMessage_ = "buffer"
+        }, token: CancellationToken.None);
+
+        // wait for 10 seconds
+        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
+        while (!TestAgent.ReceivedMessages.ContainsKey(nameof(DelegateMessageToTestAgentAsync)) && !cts.Token.IsCancellationRequested)
+        {
+            await Task.Delay(100);
+        }
+
+        TestAgent.ReceivedMessages[nameof(DelegateMessageToTestAgentAsync)].Should().NotBeNull();
+    }
+
+    /// <summary>
+    /// The test agent is a simple agent that is used for testing purposes.
+    /// </summary>
+    public class TestAgent(
+        [FromKeyedServices("AgentsMetadata")] AgentsMetadata eventTypes,
+        Logger<Agent>? logger = null) : Agent(eventTypes, logger), IHandle<TextMessage>
+    {
+        public Task Handle(TextMessage item, CancellationToken cancellationToken = default)
+        {
+            ReceivedMessages[item.Source] = item.TextMessage_;
+            return Task.CompletedTask;
+        }
+        public Task Handle(string item)
+        {
+            ReceivedItems.Add(item);
+            return Task.CompletedTask;
+        }
+        public Task Handle(int item)
+        {
+            ReceivedItems.Add(item);
+            return Task.CompletedTask;
+        }
+        public List<object> ReceivedItems { get; private set; } = [];
+
+        /// <summary>
+        /// Key: source
+        /// Value: message
+        /// </summary>
+        public static ConcurrentDictionary<string, object> ReceivedMessages { get; private set; } = new();
+    }
+}
+
+/// <summary>
+/// GrpcRuntimeFixture - provides a fixture for the agent runtime.
+/// </summary>
+/// <remarks>
+/// This fixture is used to provide a runtime for the agent tests.
+/// However, it is shared between tests. So operations from one test can affect another.
+/// </remarks>
+public sealed class GrpcRuntimeFixture
+{
+    public GrpcRuntimeFixture()
+    {
+        AppHost = StartAppHostAsync().GetAwaiter().GetResult();
+    }
+
+    private static async Task<IHost> StartAppHostAsync()
+    {
+        return await AgentsApp.StartAsync().ConfigureAwait(false);
+    }
+    public IHost AppHost { get; }
+
+    /// <summary>
+    /// Start - starts the agent
+    /// </summary>
+    /// <returns>IAgentWorker, TestAgent</returns>
+    public (IAgentWorker, TestAgent) Start()
+    {
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(AppHost.Services);
+        var worker = AppHost.Services.GetRequiredService<IAgentWorker>();
+        Agent.Initialize(worker, agent);
+        return (worker, agent);
+    }
+    /// <summary>
+    /// Stop - stops the agent
+    /// </summary>
+    /// <returns>void</returns>
+    public void Stop()
+    {
+        IHostApplicationLifetime hostApplicationLifetime = AppHost.Services.GetRequiredService<IHostApplicationLifetime>();
+        hostApplicationLifetime.StopApplication();
+    }
+}
+
+[CollectionDefinition(Name)]
+public sealed class GrpcClusterFixtureCollection : ICollectionFixture<GrpcRuntimeFixture>
+{
+    public const string Name = nameof(GrpcClusterFixtureCollection);
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj
new file mode 100644
index 000000000000..a4e37298aee1
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj
@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>$(TestTargetFrameworks)</TargetFrameworks>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <IsTestProject>True</IsTestProject>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj" />
+    <PackageReference Include="Microsoft.Extensions.Hosting" />
+  </ItemGroup>
+
+</Project>

From bf907aacbd87d6837d917c7ff0cc7464a134d701 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 12:27:56 -0800
Subject: [PATCH 025/110] update AddGrpcAgentWorker

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs   |  2 +-
 .../GrpcAgentWorkerHostBuilderExtension.cs      | 17 +++++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index 922ef8a59500..378428ab7ec6 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -20,7 +20,7 @@ public static async ValueTask<WebApplication> StartAsync(WebApplicationBuilder?
     {
         builder ??= WebApplication.CreateBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
-        builder.AddAgentWorker()
+        builder.AddGrpcAgentWorker()
             .AddAgents(agentTypes);
         builder.AddServiceDefaults();
         var app = builder.Build();
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index 34e6276b52bb..657a42430f71 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -1,9 +1,11 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // GrpcAgentWorkerHostBuilderExtension.cs
+using System.Diagnostics;
 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;
 namespace Microsoft.AutoGen.Core.Grpc;
 
@@ -43,7 +45,22 @@ public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBu
                 channelOptions.ThrowOperationCanceledOnCancellation = true;
             });
         });
+        var assemblies = AppDomain.CurrentDomain.GetAssemblies();
+        builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
         builder.Services.AddSingleton<IAgentWorker, GrpcAgentWorker>();
+        builder.Services.AddSingleton<IHostedService>(sp => (IHostedService)sp.GetRequiredService<IAgentWorker>());
+        builder.Services.AddKeyedSingleton("AgentsMetadata", (sp, key) =>
+        {
+            return ReflectionHelper.GetAgentsMetadata(assemblies);
+        });
+        builder.Services.AddSingleton((s) => {
+            var worker = s.GetRequiredService<IAgentWorker>();
+            var client = ActivatorUtilities.CreateInstance<Client>(s);
+            Agent.Initialize(worker, client);
+            return client;
+        });
+        builder.Services.AddSingleton(new AgentApplicationBuilder(builder));
+
         return builder;
     }
 }

From a2e6ca02dd7a14da66bb2f617b923078b712ea58 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 17:44:49 -0800
Subject: [PATCH 026/110] starting to fix the grpcagentworker and gateway

---
 .../Core.Grpc/GrpcAgentWorker.cs              | 10 ++--
 .../Runtime.Grpc/Abstractions/IGateway.cs     | 16 ++++---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 35 ++++++++------
 .../Services/Grpc/GrpcGatewayService.cs       | 11 +++--
 .../Services/Orleans/RegistryGrain.cs         | 48 +++++++++++++++++--
 .../AgentGrpcTests.cs                         |  2 +-
 protos/agent_worker.proto                     |  9 +++-
 7 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 29d3be57d4c2..1bd282386ef3 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -399,17 +399,21 @@ public async ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken
 
     public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
     {
-        throw new NotImplementedException();
+        var agentId = new AgentId { Type = type.Name };
+        var response = _client.GetSubscriptions(agentId);
+        return new ValueTask<List<Subscription>>([.. response.Subscriptions]);
     }
 
     public ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
     {
-        throw new NotImplementedException();
+        var response = _client.Subscribe(request, null, null, cancellationToken);
+        return new ValueTask<SubscriptionResponse>(response);
     }
 
     public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
     {
-        throw new NotImplementedException();
+        var response = _client.Unsubscribe(request, null, null, cancellationToken);
+        return new ValueTask<SubscriptionResponse>(response);
     }
 }
 
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
index 3d7044f96d87..d25c42b9dee6 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
@@ -6,11 +6,13 @@ namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 
 public interface IGateway : IGrainObserver
 {
-    ValueTask<RpcResponse> InvokeRequest(RpcRequest request);
-    ValueTask BroadcastEvent(CloudEvent evt);
-    ValueTask StoreAsync(Contracts.AgentState value);
-    ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId);
-    ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request);
-    ValueTask<SubscriptionResponse> AddSubscriptionAsync(SubscriptionRequest request);
-    Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent);
+    ValueTask<RpcResponse> InvokeRequestAsync(RpcRequest request, CancellationToken cancellationToken = default);
+    ValueTask BroadcastEventAsync(CloudEvent evt, CancellationToken cancellationToken = default);
+    ValueTask StoreAsync(Contracts.AgentState value, CancellationToken cancellationToken = default);
+    ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
+    ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request, CancellationToken cancellationToken = default);
+    ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
+    ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
+    ValueTask<SubscriptionResponse> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default);
+    Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index fe76aaa6fe99..a5b2610730d3 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -39,7 +39,7 @@ public GrpcGateway(IClusterClient clusterClient, ILogger<GrpcGateway> logger)
         _gatewayRegistry = clusterClient.GetGrain<IRegistryGrain>(0);
         _subscriptions = clusterClient.GetGrain<ISubscriptionsGrain>(0);
     }
-    public async ValueTask<RpcResponse> InvokeRequest(RpcRequest request, CancellationToken cancellationToken = default)
+    public async ValueTask<RpcResponse> InvokeRequestAsync(RpcRequest request, CancellationToken cancellationToken = default)
     {
         var agentId = (request.Target.Type, request.Target.Key);
         if (!_agentDirectory.TryGetValue(agentId, out var connection) || connection.Completion.IsCompleted == true)
@@ -66,18 +66,18 @@ public async ValueTask<RpcResponse> InvokeRequest(RpcRequest request, Cancellati
         response.RequestId = originalRequestId;
         return response;
     }
-    public async ValueTask StoreAsync(AgentState value)
+    public async ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default)
     {
         _ = value.AgentId ?? throw new ArgumentNullException(nameof(value.AgentId));
         var agentState = _clusterClient.GetGrain<IAgentGrain>($"{value.AgentId.Type}:{value.AgentId.Key}");
         await agentState.WriteStateAsync(value, value.ETag);
     }
-    public async ValueTask<AgentState> ReadAsync(AgentId agentId)
+    public async ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default)
     {
         var agentState = _clusterClient.GetGrain<IAgentGrain>($"{agentId.Type}:{agentId.Key}");
         return await agentState.ReadStateAsync();
     }
-    public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request)
+    public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request, CancellationToken cancellationToken = default)
     {
         try
         {
@@ -102,7 +102,7 @@ public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(Registe
             };
         }
     }
-    public async ValueTask<SubscriptionResponse> AddSubscriptionAsync(SubscriptionRequest request)
+    public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
     {
         try
         {
@@ -280,7 +280,7 @@ await InvokeRequestDelegate(connection, request, async request =>
                 // TODO// Activate the worker: load state
             }
             // Forward the message to the gateway and return the result.
-            return await gateway.InvokeRequest(request).ConfigureAwait(true);
+            return await gateway.InvokeRequestAsync(request).ConfigureAwait(true);
         }).ConfigureAwait(false);
     }
     private static async Task InvokeRequestDelegate(GrpcWorkerConnection connection, RpcRequest request, Func<RpcRequest, Task<RpcResponse>> func)
@@ -365,12 +365,7 @@ private async ValueTask DispatchEventToAgentsAsync(IEnumerable<string> agentType
         }
         await Task.WhenAll(tasks).ConfigureAwait(false);
     }
-
-    async ValueTask<RpcResponse> IGateway.InvokeRequest(RpcRequest request)
-    {
-        return await this.InvokeRequest(request).ConfigureAwait(false);
-    }
-    public async ValueTask BroadcastEvent(CloudEvent evt)
+    public async ValueTask BroadcastEventAsync(CloudEvent evt, CancellationToken cancellationToken = default)
     {
         var tasks = new List<Task>(_workers.Count);
         foreach (var (_, connection) in _supportedAgentTypes)
@@ -380,13 +375,23 @@ public async ValueTask BroadcastEvent(CloudEvent evt)
         }
         await Task.WhenAll(tasks).ConfigureAwait(false);
     }
-    Task IGateway.SendMessageAsync(IConnection connection, CloudEvent cloudEvent)
+    Task IGateway.SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken)
     {
-        return this.SendMessageAsync(connection, cloudEvent);
+        return this.SendMessageAsync(connection, cloudEvent, cancellationToken);
     }
-        public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
+    public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
         var queue = (GrpcWorkerConnection)connection;
         await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
     }
+
+    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
+
+    public ValueTask<SubscriptionResponse> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default)
+    {
+        throw new NotImplementedException();
+    }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index 56c5d919c3f3..276fb187df0e 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -42,14 +42,19 @@ public override async Task<SaveStateResponse> SaveState(AgentState request, Serv
             Success = true // TODO: Implement error handling
         };
     }
-    public override async Task<SubscriptionResponse> AddSubscription(SubscriptionRequest request, ServerCallContext context)
+    public override async Task<SubscriptionResponse> Subscribe(SubscriptionRequest request, ServerCallContext context)
     {
         request.RequestId = context.Peer;
-        return await Gateway.AddSubscriptionAsync(request);
+        return await Gateway.SubscribeAsync(request).ConfigureAwait(true);
+    }
+    public override async Task<SubscriptionResponse> Unsubscribe(SubscriptionRequest request, ServerCallContext context)
+    {
+        request.RequestId = context.Peer;
+        return await Gateway.UnsubscribeAsync(request).ConfigureAwait(true);
     }
     public override async Task<RegisterAgentTypeResponse> RegisterAgent(RegisterAgentTypeRequest request, ServerCallContext context)
     {
         request.RequestId = context.Peer;
-        return await Gateway.RegisterAgentTypeAsync(request);
+        return await Gateway.RegisterAgentTypeAsync(request).ConfigureAwait(true);
     }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index fab3c8b6eb63..bcb30b637a8f 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -176,6 +176,7 @@ public async ValueTask SubscribeAsync(SubscriptionRequest sub)
     {
         switch (sub.Subscription.SubscriptionCase)
         {
+            //TODO: this doesnt look right
             case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
                 break;
             case Subscription.SubscriptionOneofCase.TypeSubscription:
@@ -196,9 +197,7 @@ public async ValueTask SubscribeAsync(SubscriptionRequest sub)
                         agents = new HashSet<string>();
                         state.State.TopicToAgentTypesMap[sub.Subscription.TypeSubscription.TopicType] = agents;
                     }
-
                     agents.Add(sub.Subscription.TypeSubscription.AgentType);
-
                     break;
                 }
             default:
@@ -208,12 +207,53 @@ public async ValueTask SubscribeAsync(SubscriptionRequest sub)
     }
     public async ValueTask UnsubscribeAsync(SubscriptionRequest request)
     {
-        throw new NotImplementedException();
+        switch (request.Subscription.SubscriptionCase)
+        {
+            case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
+                break;
+            case Subscription.SubscriptionOneofCase.TypeSubscription:
+                {
+                    // remove the topic from the set of topics for the agent type
+                    state.State.AgentsToTopicsMap.TryGetValue(request.Subscription.TypeSubscription.AgentType, out var topics);
+                    if (topics is not null)
+                    {
+                        while(topics.Remove(request.Subscription.TypeSubscription.TopicType))
+                        {
+                            // ensures all instances are removed
+                        }
+                    }
+
+                    // remove the agent type from the set of agent types for the topic
+                    state.State.TopicToAgentTypesMap.TryGetValue(request.Subscription.TypeSubscription.TopicType, out var agents);
+                    if (agents is not null)
+                    {
+                        while(agents.Remove(request.Subscription.TypeSubscription.AgentType))
+                        {
+                            // ensures all instances are removed
+                        }
+                    }
+                    break;
+                }
+            default:
+                throw new InvalidOperationException("Invalid subscription type");
+        }
+        await state.WriteStateAsync().ConfigureAwait(false);
     }
 
     public ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType)
     {
-        throw new NotImplementedException();
+        var subscriptions = new Dictionary<string, List<string>>();
+        if (state.State.AgentsToTopicsMap.TryGetValue(agentType, out var topics))
+        {
+            foreach (var topic in topics)
+            {
+                if (state.State.TopicToAgentTypesMap.TryGetValue(topic, out var agents))
+                {
+                    subscriptions[topic] = agents.ToList();
+                }
+            }
+        }
+        return new(subscriptions);
     }
 
     private sealed class WorkerState
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 275b82e745e2..0b2aa05382af 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -47,7 +47,7 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     public async Task Agent_ShouldInitializeCorrectly()
     {
         var (worker, agent) = _fixture.Start();
-        Assert.Equal("AgentWorker", worker.GetType().Name);
+        Assert.Equal("GrpcAgentWorker", worker.GetType().Name);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
         _fixture.Stop();
diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index 09eb1b3fb18e..543b3fba1321 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -77,6 +77,10 @@ message Subscription {
     }
 }
 
+message SubscriptionList {
+    repeated Subscription subscriptions = 1;
+}
+
 message SubscriptionRequest {
     string request_id = 1;
     Subscription subscription = 2;
@@ -93,8 +97,9 @@ service AgentRpc {
     rpc GetState(AgentId) returns (GetStateResponse);
     rpc SaveState(AgentState) returns (SaveStateResponse);
     rpc RegisterAgent(RegisterAgentTypeRequest) returns (RegisterAgentTypeResponse);
-    rpc AddSubscription(SubscriptionRequest) returns (SubscriptionResponse);
-    rpc RemoveSubscription(SubscriptionRequest) returns (SubscriptionResponse);
+    rpc Subscribe(SubscriptionRequest) returns (SubscriptionResponse);
+    rpc Unsubscribe(SubscriptionRequest) returns (SubscriptionResponse);
+    rpc GetSubscriptions(AgentId) returns (SubscriptionList);
 }
 
 message AgentState {

From 9fc15f3ea9406008a8160f9193e1512c23c0a9ae Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 17:46:36 -0800
Subject: [PATCH 027/110] format

---
 .../dev-team/DevTeam.Backend/Program.cs       | 14 ++++++-------
 .../Services/GithubWebHookProcessor.cs        |  2 +-
 .../GrpcAgentWorkerHostBuilderExtension.cs    |  3 ++-
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    |  2 +-
 dotnet/src/Microsoft.AutoGen/Core/Client.cs   |  2 +-
 .../Core/HostBuilderExtensions.cs             |  3 ++-
 dotnet/src/Microsoft.AutoGen/Core/IHandle.cs  |  2 +-
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs |  4 ++--
 .../Services/Orleans/AgentsRegistryState.cs   |  2 +-
 .../Services/Orleans/RegistryGrain.cs         |  4 ++--
 .../Orleans/Surrogates/AgentStateSurrogate.cs | 21 +++++++++----------
 .../AgentGrpcTests.cs                         |  8 +++----
 .../AgentTests.cs                             |  8 +++----
 .../GrpcGatewayServiceTests.cs                |  2 +-
 .../Helpers/Grpc/TestGrpcClient.cs            |  2 +-
 15 files changed, 40 insertions(+), 39 deletions(-)

diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Program.cs b/dotnet/samples/dev-team/DevTeam.Backend/Program.cs
index a2ba9021c271..ee75f056c1cf 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Program.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Program.cs
@@ -2,18 +2,18 @@
 // Program.cs
 
 using Azure.Identity;
+using DevTeam.Backend.Agents;
+using DevTeam.Backend.Agents.Developer;
+using DevTeam.Backend.Agents.DeveloperLead;
+using DevTeam.Backend.Agents.ProductManager;
+using DevTeam.Backend.Services;
 using DevTeam.Options;
+using Microsoft.AutoGen.Core;
+using Microsoft.AutoGen.Core.Grpc;
 using Microsoft.Extensions.Azure;
 using Microsoft.Extensions.Options;
-using Microsoft.AutoGen.Core;
 using Octokit.Webhooks;
 using Octokit.Webhooks.AspNetCore;
-using DevTeam.Backend.Services;
-using DevTeam.Backend.Agents;
-using DevTeam.Backend.Agents.ProductManager;
-using DevTeam.Backend.Agents.DeveloperLead;
-using DevTeam.Backend.Agents.Developer;
-using Microsoft.AutoGen.Core.Grpc;
 
 var builder = WebApplication.CreateBuilder(args);
 
diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs
index 7264f5621311..b3d0b1aa2f5c 100644
--- a/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs
+++ b/dotnet/samples/dev-team/DevTeam.Backend/Services/GithubWebHookProcessor.cs
@@ -116,7 +116,7 @@ private async Task HandleClosingIssue(long issueNumber, string skillName, string
 
         IMessage evt = (skillName, functionName) switch
         {
-            ("PM", "Readme") => new ReadmeChainClosed {  },
+            ("PM", "Readme") => new ReadmeChainClosed { },
             ("DevLead", "Plan") => new DevPlanChainClosed { },
             ("Developer", "Implement") => new CodeChainClosed { },
             _ => new CloudEvent() // TODO: default event
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index 657a42430f71..fe8aaefa484d 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -53,7 +53,8 @@ public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBu
         {
             return ReflectionHelper.GetAgentsMetadata(assemblies);
         });
-        builder.Services.AddSingleton((s) => {
+        builder.Services.AddSingleton((s) =>
+        {
             var worker = s.GetRequiredService<IAgentWorker>();
             var client = ActivatorUtilities.CreateInstance<Client>(s);
             Agent.Initialize(worker, client);
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 9385d9fda223..c70f50446919 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -297,7 +297,7 @@ static async (state, ct) =>
     /// <param name="key">The source of the message.</param>
     /// <param name="token">A token to cancel the operation.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    public async ValueTask PublishMessageAsync<T>(T @event, string? topic = null, string? key = null, CancellationToken token = default ) where T : IMessage
+    public async ValueTask PublishMessageAsync<T>(T @event, string? topic = null, string? key = null, CancellationToken token = default) where T : IMessage
     {
         var k = string.IsNullOrWhiteSpace(key) ? AgentId.Key : key;
         var topicType = string.IsNullOrWhiteSpace(topic) ? "default" : topic;
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Client.cs b/dotnet/src/Microsoft.AutoGen/Core/Client.cs
index f689751b4002..132dcd998c5c 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Client.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Client.cs
@@ -6,4 +6,4 @@ namespace Microsoft.AutoGen.Core;
 public sealed class Client([FromKeyedServices("AgentsMetadata")] AgentsMetadata eventTypes)
     : Agent(eventTypes)
 {
-}
\ No newline at end of file
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
index e48195c63a6e..339ea6fd12b2 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/HostBuilderExtensions.cs
@@ -35,7 +35,8 @@ public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilde
         {
             return ReflectionHelper.GetAgentsMetadata(assemblies);
         });
-        builder.Services.AddSingleton((s) => {
+        builder.Services.AddSingleton((s) =>
+        {
             var worker = s.GetRequiredService<IAgentWorker>();
             var client = ActivatorUtilities.CreateInstance<Client>(s);
             Agent.Initialize(worker, client);
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs b/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
index 0b91f4436d4c..cb1dd62de406 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IHandle.cs
@@ -17,4 +17,4 @@ public interface IHandle<in T> where T : IMessage
     /// <param name="item">The item to be handled.</param>
     /// <returns>A task that represents the asynchronous operation.</returns>
     Task Handle(T item, CancellationToken cancellationToken = default);
-}
\ No newline at end of file
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index a5b2610730d3..0303bb7b1d89 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -159,7 +159,7 @@ internal async Task<string> ConnectToWorkerProcess(IAsyncStreamReader<Message> r
         {
             completion.SetResult(workerProcess.Connect());
         });
-        
+
         await completion.Task;
         return connectionId;
     }
@@ -197,7 +197,7 @@ private void DispatchResponse(GrpcWorkerConnection connection, RpcResponse respo
     {
         if (!_pendingRequests.TryRemove((connection, response.RequestId), out var completion))
         {
-            _logger.LogWarning("Received response for unknown request id: {RequestId}.", response.RequestId);   
+            _logger.LogWarning("Received response for unknown request id: {RequestId}.", response.RequestId);
             return;
         }
         // Complete the request.
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
index 122821270f65..3e69bd3cc3a9 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
@@ -1,4 +1,4 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
 // AgentsRegistryState.cs
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index bcb30b637a8f..81a551accd92 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -217,7 +217,7 @@ public async ValueTask UnsubscribeAsync(SubscriptionRequest request)
                     state.State.AgentsToTopicsMap.TryGetValue(request.Subscription.TypeSubscription.AgentType, out var topics);
                     if (topics is not null)
                     {
-                        while(topics.Remove(request.Subscription.TypeSubscription.TopicType))
+                        while (topics.Remove(request.Subscription.TypeSubscription.TopicType))
                         {
                             // ensures all instances are removed
                         }
@@ -227,7 +227,7 @@ public async ValueTask UnsubscribeAsync(SubscriptionRequest request)
                     state.State.TopicToAgentTypesMap.TryGetValue(request.Subscription.TypeSubscription.TopicType, out var agents);
                     if (agents is not null)
                     {
-                        while(agents.Remove(request.Subscription.TypeSubscription.AgentType))
+                        while (agents.Remove(request.Subscription.TypeSubscription.AgentType))
                         {
                             // ensures all instances are removed
                         }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs
index 1b1df59a91bc..a5291f942155 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AgentStateSurrogate.cs
@@ -29,18 +29,17 @@ public sealed class AgentStateSurrogateConverter :
 {
     public AgentState ConvertFromSurrogate(
         in AgentStateSurrogate surrogate)
+    {
+        var agentState = new AgentState
         {
-            var agentState = new AgentState
-            {
-                AgentId = surrogate.AgentId,
-                BinaryData = surrogate.BinaryData,
-                TextData = surrogate.TextData,
-                ETag = surrogate.Etag
-            };
-            //agentState.ProtoData = surrogate.ProtoData;
-            return agentState;
-        }
-        
+            AgentId = surrogate.AgentId,
+            BinaryData = surrogate.BinaryData,
+            TextData = surrogate.TextData,
+            ETag = surrogate.Etag
+        };
+        //agentState.ProtoData = surrogate.ProtoData;
+        return agentState;
+    }
 
     public AgentStateSurrogate ConvertToSurrogate(
         in AgentState value) =>
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 0b2aa05382af..d780af87e5bc 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -100,10 +100,10 @@ public async Task StoreAsync_and_ReadAsyncTest()
             { "testdata", "Active" }
         };
         await agent.StoreAsync(new AgentState
-            {
-                AgentId = agent.AgentId,
-                TextData = JsonSerializer.Serialize(state)
-            }).ConfigureAwait(true);
+        {
+            AgentId = agent.AgentId,
+            TextData = JsonSerializer.Serialize(state)
+        }).ConfigureAwait(true);
         var readState = await agent.ReadAsync<AgentState>(agent.AgentId).ConfigureAwait(true);
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 02e927b072e9..1e7b5ff10166 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -102,10 +102,10 @@ public async Task StoreAsync_and_ReadAsyncTest()
             { "testdata", "Active" }
         };
         await agent.StoreAsync(new AgentState
-            {
-                AgentId = agent.AgentId,
-                TextData = JsonSerializer.Serialize(state)
-            }).ConfigureAwait(true);
+        {
+            AgentId = agent.AgentId,
+            TextData = JsonSerializer.Serialize(state)
+        }).ConfigureAwait(true);
         var readState = await agent.ReadAsync<AgentState>(agent.AgentId).ConfigureAwait(true);
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 841264a1230a..12035da98144 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -29,7 +29,7 @@ public async Task Test_OpenChannel()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         using var client = new TestGrpcClient();
-        
+
         gateway.WorkersCount.Should().Be(0);
         await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
         gateway.WorkersCount.Should().Be(1);
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
index 78724a43bf45..6795c9f9237f 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
@@ -4,7 +4,7 @@
 using Microsoft.AutoGen.Contracts;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Grpc;
-internal sealed class TestGrpcClient: IDisposable
+internal sealed class TestGrpcClient : IDisposable
 {
     public TestAsyncStreamReader<Message> RequestStream { get; }
     public TestServerStreamWriter<Message> ResponseStream { get; }

From d69a7da3ec5c0a93dbca50544b2252e3611f3490 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 17:47:10 -0800
Subject: [PATCH 028/110] format

---
 .../AgentGrpcTests.cs                                 | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index d780af87e5bc..eadfa88cbc7a 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -47,7 +47,8 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     public async Task Agent_ShouldInitializeCorrectly()
     {
         var (worker, agent) = _fixture.Start();
-        Assert.Equal("GrpcAgentWorker", worker.GetType().Name);
+        Assert.Equal("Grpc
+        AgentWorker", worker.GetType().Name);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
         _fixture.Stop();
@@ -100,10 +101,10 @@ public async Task StoreAsync_and_ReadAsyncTest()
             { "testdata", "Active" }
         };
         await agent.StoreAsync(new AgentState
-        {
-            AgentId = agent.AgentId,
-            TextData = JsonSerializer.Serialize(state)
-        }).ConfigureAwait(true);
+            {
+                AgentId = agent.AgentId,
+                TextData = JsonSerializer.Serialize(state)
+            }).ConfigureAwait(true);
         var readState = await agent.ReadAsync<AgentState>(agent.AgentId).ConfigureAwait(true);
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);

From ad9450275c540b2fbd597fb6e31ce294e9bac886 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 7 Jan 2025 17:53:42 -0800
Subject: [PATCH 029/110] format

---
 .../Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs   | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index eadfa88cbc7a..9b5808318500 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -101,10 +101,10 @@ public async Task StoreAsync_and_ReadAsyncTest()
             { "testdata", "Active" }
         };
         await agent.StoreAsync(new AgentState
-            {
-                AgentId = agent.AgentId,
-                TextData = JsonSerializer.Serialize(state)
-            }).ConfigureAwait(true);
+        {
+            AgentId = agent.AgentId,
+            TextData = JsonSerializer.Serialize(state)
+        }).ConfigureAwait(true);
         var readState = await agent.ReadAsync<AgentState>(agent.AgentId).ConfigureAwait(true);
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);

From 11558c2ad4ff21e579af4787f5fb71b71762b598 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 8 Jan 2025 07:46:31 -0800
Subject: [PATCH 030/110] seems like there was a typo

---
 .../test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 9b5808318500..d780af87e5bc 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -47,8 +47,7 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     public async Task Agent_ShouldInitializeCorrectly()
     {
         var (worker, agent) = _fixture.Start();
-        Assert.Equal("Grpc
-        AgentWorker", worker.GetType().Name);
+        Assert.Equal("GrpcAgentWorker", worker.GetType().Name);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
         _fixture.Stop();

From c3de0ad277ef926bbbe6c9c8147a865f92570a45 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 10 Jan 2025 09:23:28 -0800
Subject: [PATCH 031/110] interim - trying to fix DI error

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs     |  2 ++
 .../Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj  |  1 +
 .../Orleans/OrleansRuntimeHostingExtenions.cs     |  2 +-
 .../Properties/launchSettings.json                | 13 +++++++++++++
 .../appsettings.json                              | 15 +++++++++++++++
 5 files changed, 32 insertions(+), 1 deletion(-)
 create mode 100644 dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Properties/launchSettings.json
 create mode 100644 dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index 378428ab7ec6..6f9645146265 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -7,6 +7,7 @@
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
+using Microsoft.AutoGen.Runtime.Grpc;
 
 namespace Microsoft.AutoGen.Core.Grpc;
 
@@ -20,6 +21,7 @@ public static async ValueTask<WebApplication> StartAsync(WebApplicationBuilder?
     {
         builder ??= WebApplication.CreateBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
+        builder.AddOrleans();
         builder.AddGrpcAgentWorker()
             .AddAgents(agentTypes);
         builder.AddServiceDefaults();
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 a56f306d04b6..9ab2d7419faf 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,6 +9,7 @@
   <ItemGroup>
     <ProjectReference Include="..\Core\Microsoft.AutoGen.Core.csproj" />
     <ProjectReference Include="..\Contracts\Microsoft.AutoGen.Contracts.csproj" />
+    <ProjectReference Include="..\Runtime.Grpc\Microsoft.AutoGen.Runtime.Grpc.csproj" />
   </ItemGroup>
 
 
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
index 68e0c7af745c..fe2ae54d3b07 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
@@ -17,7 +17,6 @@ public static class OrleansRuntimeHostingExtenions
     public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builder)
     {
         builder.Services.AddSerializer(serializer => serializer.AddProtobufSerializer());
-        builder.Services.AddSingleton<IRegistryGrain, RegistryGrain>();
 
         // Ensure Orleans is added before the hosted service to guarantee that it starts first.
         //TODO: make all of this configurable
@@ -86,6 +85,7 @@ public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builde
               .AddMemoryGrainStorage("PubSubStore");
             }
         });
+        builder.Services.AddSingleton<IRegistryGrain, RegistryGrain>();
 
         return builder;
     }
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Properties/launchSettings.json b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Properties/launchSettings.json
new file mode 100644
index 000000000000..cfddee319d65
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Properties/launchSettings.json
@@ -0,0 +1,13 @@
+{
+  "profiles": {
+    "AgentHost": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": true,
+      "applicationUrl": "https://localhost:50670;http://localhost:50673",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json
new file mode 100644
index 000000000000..ae32fe371a70
--- /dev/null
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json
@@ -0,0 +1,15 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Warning",
+      "Microsoft": "Warning",
+      "Microsoft.Orleans": "Warning"
+    }
+  },
+  "AllowedHosts": "*",
+  "Kestrel": {
+    "EndpointDefaults": {
+      "Protocols": "Http2"
+    }
+  }
+}

From 5ecf4a59b554a6132b66cd64d97eb0c7aed5fb2a Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 14 Jan 2025 13:56:04 -0800
Subject: [PATCH 032/110] attempting fix

---
 .../Services/Orleans/OrleansRuntimeHostingExtenions.cs          | 1 +
 .../Runtime.Grpc/Services/Orleans/RegistryGrain.cs              | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
index fe2ae54d3b07..5b1abc477a1a 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
@@ -28,6 +28,7 @@ public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builde
                 siloBuilder.UseLocalhostClustering()
                        .AddMemoryStreams("StreamProvider")
                        .AddMemoryGrainStorage("PubSubStore")
+                       .AddMemoryGrainStorage("AgentRegistryStore")
                        .AddMemoryGrainStorage("AgentStateStore");
 
                 siloBuilder.UseInMemoryReminderService();
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index 81a551accd92..ea9b463d2152 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -5,7 +5,7 @@
 using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
-internal sealed class RegistryGrain([PersistentState("state", "AgentStateStore")] IPersistentState<AgentsRegistryState> state) : Grain, IRegistryGrain
+internal sealed class RegistryGrain([PersistentState("state", "AgentRegistryStore")] IPersistentState<AgentsRegistryState> state) : Grain, IRegistryGrain
 {
     // TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively.
     private readonly Dictionary<IGateway, WorkerState> _workerStates = new();

From 3f29976703acbea2b1dcc6dc5be1e856d2c307e3 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 14 Jan 2025 15:56:52 -0800
Subject: [PATCH 033/110] ok, resolve the startup errors finally

---
 .../Runtime.Grpc/Abstractions/IGateway.cs     | 18 ++---
 .../Runtime.Grpc/Abstractions/IRegistry.cs    |  2 +-
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 70 +++++++++++++++++--
 .../Orleans/OrleansRuntimeHostingExtenions.cs |  9 +--
 .../Services/Orleans/RegistryGrain.cs         | 14 ++--
 5 files changed, 83 insertions(+), 30 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
index d25c42b9dee6..02aeb6bf0c3f 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
@@ -6,13 +6,13 @@ namespace Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 
 public interface IGateway : IGrainObserver
 {
-    ValueTask<RpcResponse> InvokeRequestAsync(RpcRequest request, CancellationToken cancellationToken = default);
-    ValueTask BroadcastEventAsync(CloudEvent evt, CancellationToken cancellationToken = default);
-    ValueTask StoreAsync(Contracts.AgentState value, CancellationToken cancellationToken = default);
-    ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
-    ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request, CancellationToken cancellationToken = default);
-    ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
-    ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
-    ValueTask<SubscriptionResponse> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default);
-    Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default);
+    ValueTask<RpcResponse> InvokeRequestAsync(RpcRequest request);
+    ValueTask BroadcastEventAsync(CloudEvent evt);
+    ValueTask StoreAsync(Contracts.AgentState value);
+    ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId);
+    ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request);
+    ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request);
+    ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request);
+    ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type);
+    Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
index 31ff29a0600e..08007dd4ad62 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
@@ -81,5 +81,5 @@ public interface IRegistry
     /// </summary>
     /// <param name="agentType">The type of the agent.</param>
     /// <returns>A task representing the asynchronous operation, with the subscriptions as the result.</returns>
-    ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType);
+    ValueTask<List<Subscription>> GetSubscriptions(string agentType);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 0303bb7b1d89..f423e712bdf1 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -349,7 +349,6 @@ private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, Su
         };
         await connection.ResponseStream.WriteAsync(response).ConfigureAwait(false);
     }
-
     private async ValueTask DispatchEventToAgentsAsync(IEnumerable<string> agentTypes, CloudEvent evt)
     {
         var tasks = new List<Task>(agentTypes.Count());
@@ -375,9 +374,9 @@ public async ValueTask BroadcastEventAsync(CloudEvent evt, CancellationToken can
         }
         await Task.WhenAll(tasks).ConfigureAwait(false);
     }
-    Task IGateway.SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken)
+    Task IGateway.SendMessageAsync(IConnection connection, CloudEvent cloudEvent)
     {
-        return this.SendMessageAsync(connection, cloudEvent, cancellationToken);
+        return this.SendMessageAsync(connection, cloudEvent, default);
     }
     public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
@@ -385,13 +384,70 @@ public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent
         await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
     }
 
-    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    public async ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    {
+        try
+        {
+            await _gatewayRegistry.UnsubscribeAsync(request).ConfigureAwait(true);
+            return new SubscriptionResponse
+            {
+                Success = true,
+                RequestId = request.RequestId
+            };
+        }
+        catch (Exception ex)
+        {
+            return new SubscriptionResponse
+            {
+                Success = false,
+                RequestId = request.RequestId,
+                Error = ex.Message
+            };
+        }
+    }
+
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default)
+    {
+        return _gatewayRegistry.GetSubscriptions(nameof(type));
+    }
+
+    async ValueTask<RpcResponse> IGateway.InvokeRequestAsync(RpcRequest request)
+    {
+        return await InvokeRequestAsync(request, default).ConfigureAwait(false);
+    }
+
+    async ValueTask IGateway.BroadcastEventAsync(CloudEvent evt)
+    {
+        await BroadcastEventAsync(evt, default).ConfigureAwait(false);
+    }
+
+    ValueTask IGateway.StoreAsync(AgentState value)
+    {
+        return StoreAsync(value, default);
+    }
+
+    ValueTask<AgentState> IGateway.ReadAsync(AgentId agentId)
+    {
+        return ReadAsync(agentId, default);
+    }
+
+    ValueTask<RegisterAgentTypeResponse> IGateway.RegisterAgentTypeAsync(RegisterAgentTypeRequest request)
+    {
+        return RegisterAgentTypeAsync(request, default);
+    }
+
+    ValueTask<SubscriptionResponse> IGateway.SubscribeAsync(SubscriptionRequest request)
+    {
+        return SubscribeAsync(request, default);
+    }
+
+    ValueTask<SubscriptionResponse> IGateway.UnsubscribeAsync(SubscriptionRequest request)
     {
-        throw new NotImplementedException();
+        return UnsubscribeAsync(request, default);
     }
 
-    public ValueTask<SubscriptionResponse> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default)
+    ValueTask<List<Subscription>> IGateway.GetSubscriptionsAsync(Type type)
     {
-        throw new NotImplementedException();
+        return GetSubscriptionsAsync(type, default);
     }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
index 5b1abc477a1a..e83db26ad0b7 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/OrleansRuntimeHostingExtenions.cs
@@ -3,7 +3,6 @@
 
 using System.Configuration;
 using Microsoft.AspNetCore.Builder;
-using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
@@ -41,12 +40,7 @@ public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builde
                 var cosmosDbconnectionString = builder.Configuration.GetValue<string>("Orleans:CosmosDBConnectionString") ??
                     throw new ConfigurationErrorsException(
                         "Orleans:CosmosDBConnectionString is missing from configuration. This is required for persistence in production environments.");
-                siloBuilder.Configure<ClusterOptions>(options =>
-                {
-                    //TODO: make this configurable
-                    options.ClusterId = "AutoGen-cluster";
-                    options.ServiceId = "AutoGen-cluster";
-                });
+
                 siloBuilder.Configure<SiloMessagingOptions>(options =>
                 {
                     options.ResponseTimeout = TimeSpan.FromMinutes(3);
@@ -86,7 +80,6 @@ public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builde
               .AddMemoryGrainStorage("PubSubStore");
             }
         });
-        builder.Services.AddSingleton<IRegistryGrain, RegistryGrain>();
 
         return builder;
     }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index ea9b463d2152..c3fbd58dbd43 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -240,17 +240,21 @@ public async ValueTask UnsubscribeAsync(SubscriptionRequest request)
         await state.WriteStateAsync().ConfigureAwait(false);
     }
 
-    public ValueTask<Dictionary<string, List<string>>> GetSubscriptions(string agentType)
+    public ValueTask<List<Subscription>> GetSubscriptions(string agentType)
     {
-        var subscriptions = new Dictionary<string, List<string>>();
+        var subscriptions = new List<Subscription>();
         if (state.State.AgentsToTopicsMap.TryGetValue(agentType, out var topics))
         {
             foreach (var topic in topics)
             {
-                if (state.State.TopicToAgentTypesMap.TryGetValue(topic, out var agents))
+                subscriptions.Add(new Subscription
                 {
-                    subscriptions[topic] = agents.ToList();
-                }
+                    TypeSubscription = new TypeSubscription
+                    {
+                        AgentType = agentType,
+                        TopicType = topic
+                    }
+                });
             }
         }
         return new(subscriptions);

From 7aee5c9c7e3eadd8e0153c9cdfa4b45544ffe7f0 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 14 Jan 2025 15:59:04 -0800
Subject: [PATCH 034/110] format

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index 6f9645146265..d453606146a9 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -4,10 +4,10 @@
 using System.Diagnostics.CodeAnalysis;
 using Google.Protobuf;
 using Microsoft.AspNetCore.Builder;
+using Microsoft.AutoGen.Runtime.Grpc;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
-using Microsoft.AutoGen.Runtime.Grpc;
 
 namespace Microsoft.AutoGen.Core.Grpc;
 

From 632e934778ca237fe3aa54f5e3daf21e7a55f065 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 15 Jan 2025 11:24:36 -0800
Subject: [PATCH 035/110] set Dev env for tests

---
 dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index d780af87e5bc..383de27c6ef7 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -216,6 +216,7 @@ public sealed class GrpcRuntimeFixture
 {
     public GrpcRuntimeFixture()
     {
+        Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
         AppHost = StartAppHostAsync().GetAwaiter().GetResult();
     }
 

From 0d9bf518dfe342583c08bc2c11d5c29f4e139a81 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 15 Jan 2025 13:31:40 -0800
Subject: [PATCH 036/110] checkpoint

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs    |  3 ---
 .../Microsoft.AutoGen.Runtime.Grpc.csproj        |  1 +
 .../Services/AgentWorkerHostingExtensions.cs     |  5 +++++
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs    |  4 ++++
 .../Services/Grpc/GrpcGatewayService.cs          |  5 +++++
 .../AgentGrpcTests.cs                            | 16 +++++++++++++---
 .../Microsoft.AutoGen.Core.Grpc.Tests.csproj     |  1 +
 7 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index d453606146a9..5d72bc5eda5e 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -4,7 +4,6 @@
 using System.Diagnostics.CodeAnalysis;
 using Google.Protobuf;
 using Microsoft.AspNetCore.Builder;
-using Microsoft.AutoGen.Runtime.Grpc;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
@@ -21,12 +20,10 @@ public static async ValueTask<WebApplication> StartAsync(WebApplicationBuilder?
     {
         builder ??= WebApplication.CreateBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
-        builder.AddOrleans();
         builder.AddGrpcAgentWorker()
             .AddAgents(agentTypes);
         builder.AddServiceDefaults();
         var app = builder.Build();
-        app.MapDefaultEndpoints();
         Host = app;
         await app.StartAsync().ConfigureAwait(false);
         return Host;
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Microsoft.AutoGen.Runtime.Grpc.csproj b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Microsoft.AutoGen.Runtime.Grpc.csproj
index 27474cef7900..b874a657d8f2 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Microsoft.AutoGen.Runtime.Grpc.csproj
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Microsoft.AutoGen.Runtime.Grpc.csproj
@@ -6,6 +6,7 @@
   </PropertyGroup>
   <ItemGroup>
     <ProjectReference Include="..\Contracts\Microsoft.AutoGen.Contracts.csproj" />
+    <ProjectReference Include="..\Core\Microsoft.AutoGen.Core.csproj" />
   </ItemGroup>
   <ItemGroup>
     <PackageReference Include="Microsoft.Orleans.Reminders" />
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs
index bd2ecfa9a8a7..4c1ec149ab8a 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs
@@ -6,6 +6,7 @@
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
+using Microsoft.AutoGen.Core;
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
 public static class AgentWorkerHostingExtensions
@@ -17,6 +18,10 @@ public static WebApplicationBuilder AddAgentService(this WebApplicationBuilder b
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
 
         builder.Services.AddGrpc();
+        builder.Services.AddKeyedSingleton("AgentsMetadata", (sp, key) =>
+        {
+            return ReflectionHelper.GetAgentsMetadata(AppDomain.CurrentDomain.GetAssemblies());
+        });
         builder.Services.AddSingleton<GrpcGateway>();
         builder.Services.AddSingleton<IHostedService>(sp => (IHostedService)sp.GetRequiredService<GrpcGateway>());
 
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index f423e712bdf1..cc66529083d9 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -410,6 +410,10 @@ public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type, Cancellati
     {
         return _gatewayRegistry.GetSubscriptions(nameof(type));
     }
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(string type, CancellationToken cancellationToken = default)
+    {
+        return _gatewayRegistry.GetSubscriptions(type);
+    }
 
     async ValueTask<RpcResponse> IGateway.InvokeRequestAsync(RpcRequest request)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index 276fb187df0e..18ca0b407a9a 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -52,6 +52,11 @@ public override async Task<SubscriptionResponse> Unsubscribe(SubscriptionRequest
         request.RequestId = context.Peer;
         return await Gateway.UnsubscribeAsync(request).ConfigureAwait(true);
     }
+    public override async Task<SubscriptionList> GetSubscriptions(AgentId request, ServerCallContext context)
+    {
+        var subscriptions = await Gateway.GetSubscriptionsAsync(request.Type);
+        return new SubscriptionList { Subscriptions = { subscriptions } };
+    }
     public override async Task<RegisterAgentTypeResponse> RegisterAgent(RegisterAgentTypeRequest request, ServerCallContext context)
     {
         request.RequestId = context.Peer;
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 383de27c6ef7..505a32cdc18d 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -217,13 +217,23 @@ public sealed class GrpcRuntimeFixture
     public GrpcRuntimeFixture()
     {
         Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
+        Environment.SetEnvironmentVariable("ASPNETCORE_HTTPS_PORTS", "53071");
+        Environment.SetEnvironmentVariable("AGENT_HOST", "https://localhost:53071");
         AppHost = StartAppHostAsync().GetAwaiter().GetResult();
+        Environment.SetEnvironmentVariable("ASPNETCORE_URLS", "https://+;http://+");
+        Client = StartClientAsync().GetAwaiter().GetResult();
     }
 
-    private static async Task<IHost> StartAppHostAsync()
+    private static async Task<IHost> StartClientAsync()
     {
         return await AgentsApp.StartAsync().ConfigureAwait(false);
     }
+    private static async Task<IHost> StartAppHostAsync()
+    {
+        return await Microsoft.AutoGen.Runtime.Grpc.Host.StartAsync(local: false, useGrpc: true).ConfigureAwait(false);
+
+    }
+    public IHost Client { get; }
     public IHost AppHost { get; }
 
     /// <summary>
@@ -232,8 +242,8 @@ private static async Task<IHost> StartAppHostAsync()
     /// <returns>IAgentWorker, TestAgent</returns>
     public (IAgentWorker, TestAgent) Start()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(AppHost.Services);
-        var worker = AppHost.Services.GetRequiredService<IAgentWorker>();
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(Client.Services);
+        var worker = Client.Services.GetRequiredService<IAgentWorker>();
         Agent.Initialize(worker, agent);
         return (worker, agent);
     }
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj
index a4e37298aee1..f14497e75fbc 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/Microsoft.AutoGen.Core.Grpc.Tests.csproj
@@ -10,6 +10,7 @@
   <ItemGroup>
     <ProjectReference Include="..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
     <ProjectReference Include="..\..\src\Microsoft.AutoGen\Core.Grpc\Microsoft.AutoGen.Core.Grpc.csproj" />
+    <ProjectReference Include="..\..\src\Microsoft.AutoGen\AgentHost\Microsoft.AutoGen.AgentHost.csproj" />
     <PackageReference Include="Microsoft.Extensions.Hosting" />
   </ItemGroup>
 

From 1e06db2f9564c02215a24adb25c20855d71de3c3 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 15 Jan 2025 13:51:37 -0800
Subject: [PATCH 037/110] cleanup

---
 .../Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs  |  3 +--
 .../Services/Orleans/AgentStateGrain.cs             | 13 ++++++++++++-
 2 files changed, 13 insertions(+), 3 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 1bd282386ef3..7292549312fd 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -40,8 +40,7 @@ public sealed class GrpcAgentWorker(
     private Task? _readTask;
     private Task? _writeTask;
 
-    IServiceProvider IAgentWorker.ServiceProvider => throw new NotImplementedException();
-
+    IServiceProvider IAgentWorker.ServiceProvider => ServiceProvider;
     public void Dispose()
     {
         _outboundMessagesChannel.Writer.TryComplete();
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentStateGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentStateGrain.cs
index 9d46be929ea9..e926f374a61e 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentStateGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentStateGrain.cs
@@ -2,10 +2,11 @@
 // AgentStateGrain.cs
 
 using Microsoft.AutoGen.Contracts;
+using Microsoft.AutoGen.Runtime.Grpc.Abstractions;
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
 
-internal sealed class AgentStateGrain([PersistentState("state", "AgentStateStore")] IPersistentState<AgentState> state) : Grain, IAgentState
+internal sealed class AgentStateGrain([PersistentState("state", "AgentStateStore")] IPersistentState<AgentState> state) : Grain, IAgentState, IAgentGrain
 {
     /// <inheritdoc />
     public async ValueTask<string> WriteStateAsync(AgentState newState, string eTag, CancellationToken cancellationToken = default)
@@ -33,4 +34,14 @@ public ValueTask<AgentState> ReadStateAsync(CancellationToken cancellationToken
     {
         return ValueTask.FromResult(state.State);
     }
+
+    ValueTask<AgentState> IAgentGrain.ReadStateAsync()
+    {
+        return ReadStateAsync();
+    }
+
+    ValueTask<string> IAgentGrain.WriteStateAsync(AgentState state, string eTag)
+    {
+        return WriteStateAsync(state, eTag);
+    }
 }

From 6ae606733b01725c061ba9ec74d5feae8fb25bfe Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 17 Jan 2025 11:53:39 -0800
Subject: [PATCH 038/110] stashy

---
 dotnet/samples/Hello/Hello.AppHost/Program.cs   |  2 +-
 .../AgentHost/Properties/launchSettings.json    |  2 +-
 .../AgentHost/appsettings.json                  |  5 ++++-
 .../AgentGrpcTests.cs                           | 17 +++++++++++------
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/dotnet/samples/Hello/Hello.AppHost/Program.cs b/dotnet/samples/Hello/Hello.AppHost/Program.cs
index 8230a5b7c2d9..31dbeb8c2db7 100644
--- a/dotnet/samples/Hello/Hello.AppHost/Program.cs
+++ b/dotnet/samples/Hello/Hello.AppHost/Program.cs
@@ -12,7 +12,7 @@
     .WaitFor(backend);
 #pragma warning disable ASPIREHOSTINGPYTHON001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
 // xlang is over http for now - in prod use TLS between containers
-builder.AddPythonApp("HelloAgentsPython", "../../../../python/packages/autogen-core/samples/xlang/hello_python_agent", "hello_python_agent.py", "../../../../../.venv")
+builder.AddPythonApp("HelloAgentsPython", "../../../../python/samples/core_xlang_hello_python_agent", "hello_python_agent.py", "../../.venv")
     .WithReference(backend)
     .WithEnvironment("AGENT_HOST", backend.GetEndpoint("http"))
     .WithEnvironment("STAY_ALIVE_ON_GOODBYE", "true")
diff --git a/dotnet/src/Microsoft.AutoGen/AgentHost/Properties/launchSettings.json b/dotnet/src/Microsoft.AutoGen/AgentHost/Properties/launchSettings.json
index cfddee319d65..796802878eb5 100644
--- a/dotnet/src/Microsoft.AutoGen/AgentHost/Properties/launchSettings.json
+++ b/dotnet/src/Microsoft.AutoGen/AgentHost/Properties/launchSettings.json
@@ -4,7 +4,7 @@
       "commandName": "Project",
       "dotnetRunMessages": true,
       "launchBrowser": true,
-      "applicationUrl": "https://localhost:50670;http://localhost:50673",
+      "applicationUrl": "https://localhost:53071;http://localhost:50673",
       "environmentVariables": {
         "ASPNETCORE_ENVIRONMENT": "Development"
       }
diff --git a/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json b/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
index ae32fe371a70..1739187e77b2 100644
--- a/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
+++ b/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
@@ -3,7 +3,10 @@
     "LogLevel": {
       "Default": "Warning",
       "Microsoft": "Warning",
-      "Microsoft.Orleans": "Warning"
+      "Microsoft.Hosting.Lifetime": "Information",
+      "Microsoft.AspNetCore": "Information",
+      "Microsoft.Orleans": "Warning",
+      "Orleans.Runtime": "Warning"
     }
   },
   "AllowedHosts": "*",
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 505a32cdc18d..fd825d93cc65 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -18,7 +18,6 @@ namespace Microsoft.AutoGen.Core.Grpc.Tests;
 [Collection(GrpcClusterFixtureCollection.Name)]
 public class AgentGrpcTests(GrpcRuntimeFixture fixture)
 {
-    private readonly IServiceProvider _serviceProvider = fixture.AppHost.Services;
     private readonly GrpcRuntimeFixture _fixture = fixture;
     // need a variable to store the runtime instance
     public static WebApplication? Host { get; private set; }
@@ -30,7 +29,7 @@ public class AgentGrpcTests(GrpcRuntimeFixture fixture)
     [Fact]
     public async Task Agent_ShouldThrowException_WhenNotInitialized()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_fixture.Client.Services);
         await Assert.ThrowsAsync<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(
             async () =>
             {
@@ -130,12 +129,18 @@ public async Task PublishMessageAsync_and_ReceiveMessageTest()
             }
         }
         Assert.True(found);
+/*         await AgentsApp.PublishMessageAsync("TestEvent", new TextMessage()
+        {
+            Source = "TestEvent",
+            TextMessage_ = "buffer"
+        }, local: false).ConfigureAwait(true);
+ */         
         await agent.PublishMessageAsync(new TextMessage()
         {
             Source = "TestEvent",
             TextMessage_ = "buffer"
         }).ConfigureAwait(true);
-        await Task.Delay(100);
+        await Task.Delay(10000);
         Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
         _fixture.Stop();
     }
@@ -156,7 +161,7 @@ public async Task InvokeCorrectHandler()
     [Fact]
     public async Task DelegateMessageToTestAgentAsync()
     {
-        var client = _fixture.AppHost.Services.GetRequiredService<Client>();
+        var client = _fixture.Client.Services.GetRequiredService<Client>();
         await client.PublishMessageAsync(new TextMessage()
         {
             Source = nameof(DelegateMessageToTestAgentAsync),
@@ -234,7 +239,7 @@ private static async Task<IHost> StartAppHostAsync()
 
     }
     public IHost Client { get; }
-    public IHost AppHost { get; }
+    public IHost? AppHost { get; }
 
     /// <summary>
     /// Start - starts the agent
@@ -253,7 +258,7 @@ private static async Task<IHost> StartAppHostAsync()
     /// <returns>void</returns>
     public void Stop()
     {
-        IHostApplicationLifetime hostApplicationLifetime = AppHost.Services.GetRequiredService<IHostApplicationLifetime>();
+        IHostApplicationLifetime hostApplicationLifetime = Client.Services.GetRequiredService<IHostApplicationLifetime>();
         hostApplicationLifetime.StopApplication();
     }
 }

From 6215c5d089190613afcd484773175ee745aea002 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 17 Jan 2025 14:58:05 -0800
Subject: [PATCH 039/110] remove failed experiment

---
 .../Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs    | 7 +------
 1 file changed, 1 insertion(+), 6 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index fd825d93cc65..f6005d1c8053 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -129,12 +129,7 @@ public async Task PublishMessageAsync_and_ReceiveMessageTest()
             }
         }
         Assert.True(found);
-/*         await AgentsApp.PublishMessageAsync("TestEvent", new TextMessage()
-        {
-            Source = "TestEvent",
-            TextMessage_ = "buffer"
-        }, local: false).ConfigureAwait(true);
- */         
+  
         await agent.PublishMessageAsync(new TextMessage()
         {
             Source = "TestEvent",

From 709303417865d64b8fb6208c8304bd2d9c727c68 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 17 Jan 2025 15:21:27 -0800
Subject: [PATCH 040/110] back AgentsApp off of ASPNET

---
 dotnet/src/Microsoft.AutoGen/Core/App.cs | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/App.cs b/dotnet/src/Microsoft.AutoGen/Core/App.cs
index f0850e29ed3a..e8d84789f71b 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/App.cs
@@ -3,7 +3,6 @@
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using Google.Protobuf;
-using Microsoft.AspNetCore.Builder;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
@@ -13,27 +12,25 @@ namespace Microsoft.AutoGen.Core;
 public static class AgentsApp
 {
     // need a variable to store the runtime instance
-    public static WebApplication? Host { get; private set; }
+    public static IHost? Host { get; private set; }
 
     [MemberNotNull(nameof(Host))]
-    public static async ValueTask<WebApplication> StartAsync(WebApplicationBuilder? builder = null, AgentTypes? agentTypes = null)
+    public static async ValueTask<IHost> StartAsync(HostApplicationBuilder? builder = null, AgentTypes? agentTypes = null)
     {
-        builder ??= WebApplication.CreateBuilder();
+        builder ??= new HostApplicationBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
         builder.AddAgentWorker()
             .AddAgents(agentTypes);
-        builder.AddServiceDefaults();
         var app = builder.Build();
 
-        app.MapDefaultEndpoints();
         Host = app;
         await app.StartAsync().ConfigureAwait(false);
         return Host;
     }
-    public static async ValueTask<WebApplication> PublishMessageAsync(
+    public static async ValueTask<IHost> PublishMessageAsync(
         string topic,
         IMessage message,
-        WebApplicationBuilder? builder = null,
+        HostApplicationBuilder? builder = null,
         AgentTypes? agents = null,
         bool local = false)
     {

From 5b297fb4921d3077c8f498a1d923e8d289238a1c Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 17 Jan 2025 15:44:36 -0800
Subject: [PATCH 041/110] back off of aspnet

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index 5d72bc5eda5e..5a38b0f3c4af 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -3,7 +3,6 @@
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using Google.Protobuf;
-using Microsoft.AspNetCore.Builder;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
@@ -13,25 +12,24 @@ namespace Microsoft.AutoGen.Core.Grpc;
 public static class AgentsApp
 {
     // need a variable to store the runtime instance
-    public static WebApplication? Host { get; private set; }
+    public static IHost? Host { get; private set; }
 
     [MemberNotNull(nameof(Host))]
-    public static async ValueTask<WebApplication> StartAsync(WebApplicationBuilder? builder = null, AgentTypes? agentTypes = null, bool local = false)
+    public static async ValueTask<IHost> StartAsync(HostApplicationBuilder? builder = null, AgentTypes? agentTypes = null, bool local = false)
     {
-        builder ??= WebApplication.CreateBuilder();
+        builder ??= new HostApplicationBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
         builder.AddGrpcAgentWorker()
             .AddAgents(agentTypes);
-        builder.AddServiceDefaults();
         var app = builder.Build();
         Host = app;
         await app.StartAsync().ConfigureAwait(false);
         return Host;
     }
-    public static async ValueTask<WebApplication> PublishMessageAsync(
+    public static async ValueTask<IHost> PublishMessageAsync(
         string topic,
         IMessage message,
-        WebApplicationBuilder? builder = null,
+        HostApplicationBuilder? builder = null,
         AgentTypes? agents = null,
         bool local = false)
     {

From 0d1e1240064d721b8c4a4dd0680f4051ec3b7b5a Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 17 Jan 2025 19:55:32 -0800
Subject: [PATCH 042/110] fixing HelloAgent so that it works with GRPC as well
 now

---
 .../Hello/HelloAgent/HelloAgent.csproj        |  1 +
 dotnet/samples/Hello/HelloAgent/Program.cs    |  2 +-
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs |  8 ++-
 .../Core.Grpc/GrpcAgentWorker.cs              | 54 ++++++++++---------
 4 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj b/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj
index 5067a673df4b..73d3f43dc0e4 100644
--- a/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj
+++ b/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj
@@ -15,6 +15,7 @@
   </ItemGroup>
 
   <ItemGroup>
+    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Agents\Microsoft.AutoGen.Agents.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Contracts\Microsoft.AutoGen.Contracts.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
diff --git a/dotnet/samples/Hello/HelloAgent/Program.cs b/dotnet/samples/Hello/HelloAgent/Program.cs
index 980c34f8617c..70c3fde7a3e7 100644
--- a/dotnet/samples/Hello/HelloAgent/Program.cs
+++ b/dotnet/samples/Hello/HelloAgent/Program.cs
@@ -8,7 +8,7 @@
 
 var local = true;
 if (Environment.GetEnvironmentVariable("AGENT_HOST") != null) { local = false; }
-var app = await AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
+var app = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
 {
     Message = "World"
 }, local: local).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index 5a38b0f3c4af..ad4db0f38295 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -19,8 +19,14 @@ public static async ValueTask<IHost> StartAsync(HostApplicationBuilder? builder
     {
         builder ??= new HostApplicationBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
-        builder.AddGrpcAgentWorker()
+        if (! local) 
+        {
+            builder.AddGrpcAgentWorker()
+            .AddAgents(agentTypes);
+        } else {
+            builder.AddAgentWorker()
             .AddAgents(agentTypes);
+        }
         var app = builder.Build();
         Host = app;
         await app.StartAsync().ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 7292549312fd..7682bc864692 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -24,6 +24,7 @@ public sealed class GrpcAgentWorker(
     private readonly ConcurrentDictionary<string, Type> _agentTypes = new();
     private readonly ConcurrentDictionary<(string Type, string Key), Agent> _agents = new();
     private readonly ConcurrentDictionary<string, (Agent Agent, string OriginalRequestId)> _pendingRequests = new();
+    private readonly ConcurrentDictionary<string, HashSet<Type>> _agentsForEvent = new();
     private readonly Channel<(Message Message, TaskCompletionSource WriteCompletionSource)> _outboundMessagesChannel = Channel.CreateBounded<(Message, TaskCompletionSource)>(new BoundedChannelOptions(1024)
     {
         AllowSynchronousContinuations = true,
@@ -76,20 +77,19 @@ private async Task RunReadPump()
                             break;
 
                         case Message.MessageOneofCase.CloudEvent:
-
-                            // HACK: Send the message to an instance of each agent type
-                            // where AgentId = (namespace: event.Namespace, name: agentType)
-                            // i.e, assume each agent type implicitly subscribes to each event.
-
                             var item = message.CloudEvent;
-
-                            foreach (var (typeName, _) in _agentTypes)
+                            if (!_agentsForEvent.TryGetValue(item.Type, out var agents))
                             {
-                                var agent = GetOrActivateAgent(new AgentId { Type = typeName, Key = item.Source });
+                                _logger.LogError($"This worker can't handle the event type '{item.Type}'.");
+                                break;
+                            }
+                            foreach (var a in agents)
+                            {
+                                var agent = GetOrActivateAgent(new AgentId { Type = a.Name, Key = item.GetSubject() });
                                 agent.ReceiveMessage(message);
                             }
-
                             break;
+
                         default:
                             throw new InvalidOperationException($"Unexpected message '{message}'.");
                     }
@@ -147,7 +147,7 @@ private async Task RunWritePump()
             {
                 // 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());
+                _logger.LogError(ex, "Error connecting to GRPC endpoint {Endpoint}. Check port and SSL settings.", channel.ToString());
                 break;
             }
             catch (Exception ex) when (!_shutdownCts.IsCancellationRequested)
@@ -177,6 +177,7 @@ private Agent GetOrActivateAgent(AgentId agentId)
             if (_agentTypes.TryGetValue(agentId.Type, out var agentType))
             {
                 agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType, this);
+                Agent.Initialize(this, agent);
                 _agents.TryAdd((agentId.Type, agentId.Key), agent);
             }
             else
@@ -195,21 +196,24 @@ private async ValueTask RegisterAgentTypeAsync(string type, Type agentType, Canc
             var events = agentType.GetInterfaces()
             .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IHandle<>))
             .Select(i => ReflectionHelper.GetMessageDescriptor(i.GetGenericArguments().First())?.FullName);
-            //var state = agentType.BaseType?.GetGenericArguments().First();
-            var topicTypes = agentType.GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
-
-            //TODO: do something with the response (like retry on error)
-            await WriteChannelAsync(new Message
+            // add the agentType to the list of agent types that handle the event
+            foreach (var evt in events)
             {
-                RegisterAgentTypeRequest = new RegisterAgentTypeRequest
+                if (!_agentsForEvent.TryGetValue(evt!, out var agents))
                 {
-                    Type = type,
-                    RequestId = Guid.NewGuid().ToString(),
-                    //TopicTypes = { topicTypes },
-                    //StateType = state?.Name,
-                    //Events = { events }
+                    agents = new HashSet<Type>();
+                    _agentsForEvent[evt!] = agents;
                 }
-            }, cancellationToken).ConfigureAwait(false);
+
+                agents.Add(agentType);
+            }
+            var topicTypes = agentType.GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
+            var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest
+            {
+                Type = type,
+                Topics = { topicTypes },
+                Events = { events }
+            }, null, null, cancellationToken);
 
             foreach (var topic in topicTypes)
             {
@@ -228,7 +232,8 @@ await WriteChannelAsync(new Message
                         }
                     }
                 };
-                await WriteChannelAsync(subscriptionRequest, cancellationToken).ConfigureAwait(true);
+                await _client.SubscribeAsync(subscriptionRequest.SubscriptionRequest, null, null, cancellationToken);
+                //await WriteChannelAsync(subscriptionRequest, cancellationToken).ConfigureAwait(true);
                 foreach (var e in events)
                 {
                     subscriptionRequest = new Message
@@ -246,7 +251,8 @@ await WriteChannelAsync(new Message
                             }
                         }
                     };
-                    await WriteChannelAsync(subscriptionRequest, cancellationToken).ConfigureAwait(true);
+                    await _client.SubscribeAsync(subscriptionRequest.SubscriptionRequest, null, null, cancellationToken);
+                    //await WriteChannelAsync(subscriptionRequest, cancellationToken).ConfigureAwait(true);
                 }
             }
         }

From 3fdd78e098607692b8a915c27479b58bd1a53138 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 17 Jan 2025 22:55:30 -0800
Subject: [PATCH 043/110] cleanup trying to get grpc to work

---
 .../Core.Grpc/GrpcAgentWorker.cs              | 21 ++++++++++++++++---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 16 +++-----------
 .../GrpcGatewayServiceTests.cs                |  4 ++--
 3 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 7682bc864692..d9d1e681fd07 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -150,10 +150,15 @@ private async Task RunWritePump()
                 _logger.LogError(ex, "Error connecting to GRPC endpoint {Endpoint}. Check port and SSL settings.", channel.ToString());
                 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.");
+                _logger.LogError(ex, $"Error writing to channel.{ex}");
                 channel = RecreateChannel(channel);
                 continue;
             }
@@ -208,12 +213,22 @@ private async ValueTask RegisterAgentTypeAsync(string type, Type agentType, Canc
                 agents.Add(agentType);
             }
             var topicTypes = agentType.GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
-            var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest
+/*             var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest
             {
                 Type = type,
                 Topics = { topicTypes },
                 Events = { events }
-            }, null, null, cancellationToken);
+            }, null, null, cancellationToken); */
+            await WriteChannelAsync(new Message
+            {
+                RegisterAgentTypeRequest = new RegisterAgentTypeRequest
+                {
+                    RequestId = Guid.NewGuid().ToString(),
+                    Type = type,
+                    Topics = { topicTypes },
+                    Events = { events }
+                }
+            }, cancellationToken).ConfigureAwait(false);
 
             foreach (var topic in topicTypes)
             {
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index cc66529083d9..57df08bf327b 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -30,7 +30,6 @@ public sealed class GrpcGateway : BackgroundService, IGateway
     private readonly ConcurrentDictionary<(string Type, string Key), GrpcWorkerConnection> _agentDirectory = new();
     // RPC
     private readonly ConcurrentDictionary<(GrpcWorkerConnection, string), TaskCompletionSource<RpcResponse>> _pendingRequests = new();
-    public int WorkersCount => _workers.Count;
     public GrpcGateway(IClusterClient clusterClient, ILogger<GrpcGateway> logger)
     {
         _logger = logger;
@@ -146,22 +145,13 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
             _logger.LogWarning(exception, "Error removing worker from registry.");
         }
     }
-    internal async Task<string> ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
+    internal Task ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
     {
         _logger.LogInformation("Received new connection from {Peer}.", context.Peer);
         var workerProcess = new GrpcWorkerConnection(this, requestStream, responseStream, context);
-        var connectionId = Guid.NewGuid().ToString();
         _workers[workerProcess] = workerProcess;
-        _workersByConnection[connectionId] = workerProcess;
-
-        var completion = new TaskCompletionSource<Task>();
-        var _ = Task.Run(() =>
-        {
-            completion.SetResult(workerProcess.Connect());
-        });
-
-        await completion.Task;
-        return connectionId;
+        _workersByConnection[context.Peer] = workerProcess;
+        return workerProcess.Completion;
     }
     internal async Task SendMessageAsync(GrpcWorkerConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 12035da98144..5be9404adc66 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -30,9 +30,9 @@ public async Task Test_OpenChannel()
         var service = new GrpcGatewayService(gateway);
         using var client = new TestGrpcClient();
 
-        gateway.WorkersCount.Should().Be(0);
+        gateway._workers.Count.Should().Be(0);
         await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-        gateway.WorkersCount.Should().Be(1);
+        gateway._workers.Count.Should().Be(1);
     }
 
     [Fact]

From 9cf866ae9715d085ce3d6c4a4552de40e3ad537e Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sat, 18 Jan 2025 11:09:31 -0800
Subject: [PATCH 044/110] host changes broke this

---
 dotnet/samples/Hello/HelloAIAgents/Program.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/samples/Hello/HelloAIAgents/Program.cs b/dotnet/samples/Hello/HelloAIAgents/Program.cs
index a5bf4b68ee46..035da0353f85 100644
--- a/dotnet/samples/Hello/HelloAIAgents/Program.cs
+++ b/dotnet/samples/Hello/HelloAIAgents/Program.cs
@@ -7,7 +7,7 @@
 using Microsoft.AutoGen.Core;
 
 // send a message to the agent
-var builder = WebApplication.CreateBuilder();
+var builder = new HostApplicationBuilder();
 // put these in your environment or appsettings.json
 builder.Configuration["HelloAIAgents:ModelType"] = "azureopenai";
 builder.Configuration["HelloAIAgents:LlmModelName"] = "gpt-3.5-turbo";

From fef95b74174a6f867f79194dfa9b4b2466672d45 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sat, 18 Jan 2025 11:44:45 -0800
Subject: [PATCH 045/110] error handling for registeragenttyperesponse

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index d9d1e681fd07..05db2e1e3700 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -75,7 +75,11 @@ private async Task RunReadPump()
                             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.CloudEvent:
                             var item = message.CloudEvent;
                             if (!_agentsForEvent.TryGetValue(item.Type, out var agents))

From 6053f92136ec7ac2ae027f550b877153668e1647 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sat, 18 Jan 2025 11:48:15 -0800
Subject: [PATCH 046/110] error handling for subscriptionresponse

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 05db2e1e3700..398c98febc84 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -80,6 +80,11 @@ private async Task RunReadPump()
                                 _logger.LogError($"Failed to register agent type '{message.RegisterAgentTypeResponse.Error}'");
                             }
                             break;
+                        case Message.MessageOneofCase.SubscriptionResponse:
+                            if (!message.SubscriptionResponse.Success){
+                                _logger.LogError($"Failed to add subscription '{message.SubscriptionResponse.Error}'");
+                            }
+                            break;
                         case Message.MessageOneofCase.CloudEvent:
                             var item = message.CloudEvent;
                             if (!_agentsForEvent.TryGetValue(item.Type, out var agents))

From 6824bb32d97a7b90ac3c4cac99805ceb60c6c7c5 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:18:59 -0800
Subject: [PATCH 047/110] updating publish message with topics

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index c70f50446919..310fac7f78f0 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -293,16 +293,23 @@ static async (state, ct) =>
     /// Publishes a message asynchronously.
     /// </summary>
     /// <typeparam name="T">The type of the message.</typeparam>
-    /// <param name="event">The message to publish.</param>
-    /// <param name="key">The source of the message.</param>
     /// <param name="token">A token to cancel the operation.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    public async ValueTask PublishMessageAsync<T>(T @event, string? topic = null, string? key = null, CancellationToken token = default) where T : IMessage
+    public async ValueTask PublishMessageAsync<T>(T message, string? source = null, CancellationToken token = default) where T : IMessage
     {
-        var k = string.IsNullOrWhiteSpace(key) ? AgentId.Key : key;
-        var topicType = string.IsNullOrWhiteSpace(topic) ? "default" : topic;
-        var evt = @event.ToCloudEvent(k, topicType);
-        await PublishEventAsync(evt, token).ConfigureAwait(false);
+        var topicTypes = this.GetType().GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
+        if (!topicTypes.Any())
+        {
+            topicTypes = topicTypes.Append(string.IsNullOrWhiteSpace(source) ? this.AgentId.Type + "." + this.AgentId.Key : source);
+        }
+        foreach (var topic in topicTypes)
+        {
+            await PublishMessageAsync(topic, message, source, token).ConfigureAwait(false);
+        }
+    }
+    public async ValueTask PublishMessageAsync<T>(string topic, T message, string? source = null, CancellationToken token = default) where T : IMessage
+    {
+        await PublishEventAsync(topic, message, token).ConfigureAwait(false);
     }
     public async ValueTask PublishEventAsync(CloudEvent item, CancellationToken cancellationToken = default)
     {

From 0abb6a391140addce74c3990cdf448509d6bd051 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:21:27 -0800
Subject: [PATCH 048/110] Orleans runtime logs to error only

---
 dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json b/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
index 1739187e77b2..484ba49169df 100644
--- a/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
+++ b/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
@@ -6,7 +6,7 @@
       "Microsoft.Hosting.Lifetime": "Information",
       "Microsoft.AspNetCore": "Information",
       "Microsoft.Orleans": "Warning",
-      "Orleans.Runtime": "Warning"
+      "Orleans.Runtime": "Error"
     }
   },
   "AllowedHosts": "*",

From 3aa7838ea5fa279a594a765bc834e127d0b7dc05 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:23:04 -0800
Subject: [PATCH 049/110] add log message on new connection

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 398c98febc84..aed6b78de10e 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -347,6 +347,8 @@ private AsyncDuplexStreamingCall<Message, Message> RecreateChannel(AsyncDuplexSt
     public async Task StartAsync(CancellationToken cancellationToken)
     {
         _channel = GetChannel();
+        _logger.LogInformation("Starting GrpcAgentWorker, connecting to gRPC endpoint "+ _client.ToString());
+
         StartCore();
 
         var tasks = new List<Task>(_agentTypes.Count);

From 00d9caf44d7a9dd1a9b26fb4defc80c235be9f54 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:23:48 -0800
Subject: [PATCH 050/110] improve log message

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index aed6b78de10e..486e6ec22a94 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -347,7 +347,7 @@ private AsyncDuplexStreamingCall<Message, Message> RecreateChannel(AsyncDuplexSt
     public async Task StartAsync(CancellationToken cancellationToken)
     {
         _channel = GetChannel();
-        _logger.LogInformation("Starting GrpcAgentWorker, connecting to gRPC endpoint "+ _client.ToString());
+        _logger.LogInformation("Starting GrpcAgentWorker, connecting to gRPC endpoint "+ Environment.GetEnvironmentVariable("AGENT_HOST"));
 
         StartCore();
 

From 518ad1535f4a8f4405973495b9821dcaf85157c5 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:24:58 -0800
Subject: [PATCH 051/110] improve log message

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 486e6ec22a94..ff075f3a20f0 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -156,7 +156,7 @@ private async Task RunWritePump()
             {
                 // 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}. Check port and SSL settings.", channel.ToString());
+                _logger.LogError(ex, "Error connecting to GRPC endpoint {Endpoint}.", Environment.GetEnvironmentVariable("AGENT_HOST"));
                 break;
             }
             catch (RpcException ex) when (ex.StatusCode == StatusCode.OK)

From b6915acc10e92e2594d1899d6519d52aed971458 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:29:04 -0800
Subject: [PATCH 052/110] consistent updates to Hello Samples

---
 .../samples/Hello/HelloAIAgents/HelloAIAgents.csproj   |  1 +
 dotnet/samples/Hello/HelloAIAgents/Program.cs          | 10 +++++-----
 dotnet/samples/Hello/HelloAgent/Program.cs             |  2 +-
 .../Hello/HelloAgentState/HelloAgentState.csproj       |  1 +
 dotnet/samples/Hello/HelloAgentState/Program.cs        |  8 +++++---
 5 files changed, 13 insertions(+), 9 deletions(-)

diff --git a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj
index f557ce91a0e3..722ef1d97635 100644
--- a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj
+++ b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj
@@ -11,6 +11,7 @@
   </ItemGroup>
 
   <ItemGroup>
+    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Agents\Microsoft.AutoGen.Agents.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Contracts\Microsoft.AutoGen.Contracts.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
diff --git a/dotnet/samples/Hello/HelloAIAgents/Program.cs b/dotnet/samples/Hello/HelloAIAgents/Program.cs
index 035da0353f85..2c35049e7099 100644
--- a/dotnet/samples/Hello/HelloAIAgents/Program.cs
+++ b/dotnet/samples/Hello/HelloAIAgents/Program.cs
@@ -22,16 +22,16 @@
 {
     { "HelloAIAgents", typeof(HelloAIAgent) }
 });
-var app = await AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
+var local = true;
+if (Environment.GetEnvironmentVariable("AGENT_HOST") != null) { local = false; }
+var app = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
 {
     Message = "World"
-}, builder, agentTypes, local: true);
-
-await app.WaitForShutdownAsync();
+}, local: local).ConfigureAwait(false);
 
 namespace Hello
 {
-    [TopicSubscription("agents")]
+    [TopicSubscription("HelloAgents")]
     public class HelloAgent(
         [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry,
         IHostApplicationLifetime hostApplicationLifetime) : ConsoleAgent(
diff --git a/dotnet/samples/Hello/HelloAgent/Program.cs b/dotnet/samples/Hello/HelloAgent/Program.cs
index 70c3fde7a3e7..dde48423d765 100644
--- a/dotnet/samples/Hello/HelloAgent/Program.cs
+++ b/dotnet/samples/Hello/HelloAgent/Program.cs
@@ -16,7 +16,7 @@
 
 namespace Hello
 {
-    [TopicSubscription("agents")]
+    [TopicSubscription("HelloAgents")]
     public class HelloAgent(
         IHostApplicationLifetime hostApplicationLifetime,
         [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : Agent(
diff --git a/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj b/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj
index 5dc534a4e435..343ea8eb8573 100644
--- a/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj
+++ b/dotnet/samples/Hello/HelloAgentState/HelloAgentState.csproj
@@ -12,6 +12,7 @@
   </ItemGroup>
 
   <ItemGroup>
+    <ProjectReference Include="../../../src/Microsoft.AutoGen/Core.Grpc/Microsoft.AutoGen.Core.Grpc.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Agents\Microsoft.AutoGen.Agents.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Contracts\Microsoft.AutoGen.Contracts.csproj" />
     <ProjectReference Include="..\..\..\src\Microsoft.AutoGen\Core\Microsoft.AutoGen.Core.csproj" />
diff --git a/dotnet/samples/Hello/HelloAgentState/Program.cs b/dotnet/samples/Hello/HelloAgentState/Program.cs
index 013d70786551..f81ecdad977b 100644
--- a/dotnet/samples/Hello/HelloAgentState/Program.cs
+++ b/dotnet/samples/Hello/HelloAgentState/Program.cs
@@ -7,16 +7,18 @@
 using Microsoft.AutoGen.Core;
 
 // send a message to the agent
-var app = await AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
+var local = true;
+if (Environment.GetEnvironmentVariable("AGENT_HOST") != null) { local = false; }
+var app = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
 {
     Message = "World"
-}, local: false);
+}, local: local).ConfigureAwait(false);
 
 await app.WaitForShutdownAsync();
 
 namespace Hello
 {
-    [TopicSubscription("agents")]
+    [TopicSubscription("HelloAgents")]
     public class HelloAgent(
         IHostApplicationLifetime hostApplicationLifetime,
         [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : Agent(

From 281bff286462f40f68483314f883a5e163a970fa Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Sun, 19 Jan 2025 15:31:25 -0800
Subject: [PATCH 053/110] setup dotnet 8 version

---
 .github/workflows/dotnet-build.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index f9683527f38e..a8f7eae1bf71 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -132,6 +132,10 @@ jobs:
     - name: Prepare python venv
       run: |
         source ${{ github.workspace }}/python/.venv/bin/activate
+    - name: Setup .NET 8.0
+      uses: actions/setup-dotnet@v4
+      with:
+          dotnet-version: '8.0.x'
     - name: Setup .NET 9.0
       uses: actions/setup-dotnet@v4
       with:

From 5f133a88556063c56b9398b819de7c31ae8d46b5 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 10:37:36 -0800
Subject: [PATCH 054/110] interim commit - expanding the range of
 publishmessage available

---
 dotnet/samples/Hello/HelloAIAgents/Program.cs |  4 +-
 .../IOAgent/ConsoleAgent/IHandleConsole.cs    |  2 +-
 dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs |  6 ++-
 .../Core.Grpc/GrpcAgentWorker.cs              | 20 +++++----
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 45 +++++++++++++++----
 .../Services/AgentWorkerHostingExtensions.cs  |  2 +-
 .../AgentGrpcTests.cs                         |  2 +-
 7 files changed, 56 insertions(+), 25 deletions(-)

diff --git a/dotnet/samples/Hello/HelloAIAgents/Program.cs b/dotnet/samples/Hello/HelloAIAgents/Program.cs
index 2c35049e7099..f49f5fcfb3e3 100644
--- a/dotnet/samples/Hello/HelloAIAgents/Program.cs
+++ b/dotnet/samples/Hello/HelloAIAgents/Program.cs
@@ -18,13 +18,13 @@
 }
 builder.Configuration["ConectionStrings:HelloAIAgents"] = Environment.GetEnvironmentVariable("AZURE_OPENAI_CONNECTION_STRING");
 builder.AddChatCompletionService("HelloAIAgents");
-var agentTypes = new AgentTypes(new Dictionary<string, Type>
+var _ = new AgentTypes(new Dictionary<string, Type>
 {
     { "HelloAIAgents", typeof(HelloAIAgent) }
 });
 var local = true;
 if (Environment.GetEnvironmentVariable("AGENT_HOST") != null) { local = false; }
-var app = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
+var _ = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
 {
     Message = "World"
 }, local: local).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
index cd0fa71eca0d..f73a9a6c71ee 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
@@ -10,7 +10,7 @@ namespace Microsoft.AutoGen.Agents;
 public interface IHandleConsole : IHandle<Output>, IHandle<Input>
 {
     AgentId AgentId { get; }
-    ValueTask PublishMessageAsync<T>(T message, string? source = null, string? key = null, CancellationToken token = default) where T : IMessage;
+    ValueTask PublishMessageAsync<T>(T message, string? topic = null, string? source = null, string? key = null, CancellationToken token = default) where T : IMessage;
 
     async Task IHandle<Output>.Handle(Output item, CancellationToken cancellationToken)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
index ad4db0f38295..f5c0dabe8227 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/App.cs
@@ -19,11 +19,13 @@ public static async ValueTask<IHost> StartAsync(HostApplicationBuilder? builder
     {
         builder ??= new HostApplicationBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
-        if (! local) 
+        if (!local)
         {
             builder.AddGrpcAgentWorker()
             .AddAgents(agentTypes);
-        } else {
+        }
+        else
+        {
             builder.AddAgentWorker()
             .AddAgents(agentTypes);
         }
diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index ff075f3a20f0..d4b6b2ed4ac5 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -76,12 +76,14 @@ private async Task RunReadPump()
                             request.Agent.ReceiveMessage(message);
                             break;
                         case Message.MessageOneofCase.RegisterAgentTypeResponse:
-                            if (!message.RegisterAgentTypeResponse.Success){
+                            if (!message.RegisterAgentTypeResponse.Success)
+                            {
                                 _logger.LogError($"Failed to register agent type '{message.RegisterAgentTypeResponse.Error}'");
                             }
                             break;
                         case Message.MessageOneofCase.SubscriptionResponse:
-                            if (!message.SubscriptionResponse.Success){
+                            if (!message.SubscriptionResponse.Success)
+                            {
                                 _logger.LogError($"Failed to add subscription '{message.SubscriptionResponse.Error}'");
                             }
                             break;
@@ -222,12 +224,12 @@ private async ValueTask RegisterAgentTypeAsync(string type, Type agentType, Canc
                 agents.Add(agentType);
             }
             var topicTypes = agentType.GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
-/*             var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest
-            {
-                Type = type,
-                Topics = { topicTypes },
-                Events = { events }
-            }, null, null, cancellationToken); */
+            /*             var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest
+                        {
+                            Type = type,
+                            Topics = { topicTypes },
+                            Events = { events }
+                        }, null, null, cancellationToken); */
             await WriteChannelAsync(new Message
             {
                 RegisterAgentTypeRequest = new RegisterAgentTypeRequest
@@ -347,7 +349,7 @@ private AsyncDuplexStreamingCall<Message, Message> RecreateChannel(AsyncDuplexSt
     public async Task StartAsync(CancellationToken cancellationToken)
     {
         _channel = GetChannel();
-        _logger.LogInformation("Starting GrpcAgentWorker, connecting to gRPC endpoint "+ Environment.GetEnvironmentVariable("AGENT_HOST"));
+        _logger.LogInformation("Starting GrpcAgentWorker, connecting to gRPC endpoint " + Environment.GetEnvironmentVariable("AGENT_HOST"));
 
         StartCore();
 
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 310fac7f78f0..957ee5828bec 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -289,27 +289,58 @@ static async (state, ct) =>
         // Return the result from the already-completed task
         return await completion.Task.ConfigureAwait(false);
     }
+
+    private string SetTopic(string? topic = null , string? source = null, string? key = null)
+    {
+        if (string.IsNullOrWhiteSpace(topic))
+        {
+            topic = this.AgentId.Type + "." + this.AgentId.Key;
+        }
+        topic = topic + "." + source + "." + key;
+        return topic;
+    }
+
     /// <summary>
     /// Publishes a message asynchronously.
     /// </summary>
     /// <typeparam name="T">The type of the message.</typeparam>
     /// <param name="token">A token to cancel the operation.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    public async ValueTask PublishMessageAsync<T>(T message, string? source = null, CancellationToken token = default) where T : IMessage
+    public async ValueTask PublishMessageAsync<T>(T message, string topic, string source, string key, CancellationToken token = default) where T : IMessage
     {
+        
         var topicTypes = this.GetType().GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
         if (!topicTypes.Any())
         {
             topicTypes = topicTypes.Append(string.IsNullOrWhiteSpace(source) ? this.AgentId.Type + "." + this.AgentId.Key : source);
         }
-        foreach (var topic in topicTypes)
+        topicTypes = topicTypes.Append(SetTopic(topic, source, key));
+        foreach (var t in topicTypes)
         {
-            await PublishMessageAsync(topic, message, source, token).ConfigureAwait(false);
+            await PublishEventAsync(t, message, token).ConfigureAwait(false);
         }
     }
-    public async ValueTask PublishMessageAsync<T>(string topic, T message, string? source = null, CancellationToken token = default) where T : IMessage
+    public async ValueTask PublishMessageAsync<T>(T message, string topic, string source, CancellationToken token = default) where T : IMessage
+    {
+        string key = this.AgentId.Key;
+        await PublishMessageAsync(message, topic, source, key, token).ConfigureAwait(false);
+    }
+    public async ValueTask PublishMessageAsync<T>(T message, string topic, CancellationToken token = default) where T : IMessage
+    {
+        string source = this.AgentId.Type;
+        string key = this.AgentId.Key;
+        await PublishMessageAsync(message, topic, source, key, token).ConfigureAwait(false);
+    }
+    public async ValueTask PublishMessageAsync<T>(T message, CancellationToken token = default) where T : IMessage
     {
-        await PublishEventAsync(topic, message, token).ConfigureAwait(false);
+        string topic = "";
+        string source = this.AgentId.Type;
+        string key = this.AgentId.Key;
+        await PublishMessageAsync(message, topic, source, key, token).ConfigureAwait(false);
+    }
+    public async ValueTask PublishEventAsync(string topic, IMessage message, CancellationToken cancellationToken = default)
+    {
+        await PublishEventAsync(message.ToCloudEvent(key: GetType().Name, topic: topic), cancellationToken).ConfigureAwait(false);
     }
     public async ValueTask PublishEventAsync(CloudEvent item, CancellationToken cancellationToken = default)
     {
@@ -391,8 +422,4 @@ public virtual async Task HandleObjectAsync(object item, CancellationToken cance
         // otherwise, complain
         _logger.LogError($"No handler found for type {item.GetType().FullName}");
     }
-    public async ValueTask PublishEventAsync(string topic, IMessage evt, CancellationToken cancellationToken = default)
-    {
-        await PublishEventAsync(evt.ToCloudEvent(key: GetType().Name, topic: topic), cancellationToken).ConfigureAwait(false);
-    }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs
index 4c1ec149ab8a..3b130ca4bed5 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/AgentWorkerHostingExtensions.cs
@@ -3,10 +3,10 @@
 
 using System.Diagnostics;
 using Microsoft.AspNetCore.Builder;
+using Microsoft.AutoGen.Core;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
 using Microsoft.Extensions.Hosting;
-using Microsoft.AutoGen.Core;
 
 namespace Microsoft.AutoGen.Runtime.Grpc;
 public static class AgentWorkerHostingExtensions
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index f6005d1c8053..6fd2d495d7a8 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -129,7 +129,7 @@ public async Task PublishMessageAsync_and_ReceiveMessageTest()
             }
         }
         Assert.True(found);
-  
+
         await agent.PublishMessageAsync(new TextMessage()
         {
             Source = "TestEvent",

From 05e141a4b4c7b05fa29c06c5a88dc0d8fa552920 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 10:42:51 -0800
Subject: [PATCH 055/110] fix interface in Ihandleconsole and cleanup in
 HelloAIAgent

---
 dotnet/samples/Hello/HelloAIAgents/Program.cs                  | 3 ++-
 .../Agents/IOAgent/ConsoleAgent/IHandleConsole.cs              | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/dotnet/samples/Hello/HelloAIAgents/Program.cs b/dotnet/samples/Hello/HelloAIAgents/Program.cs
index f49f5fcfb3e3..541539fb6786 100644
--- a/dotnet/samples/Hello/HelloAIAgents/Program.cs
+++ b/dotnet/samples/Hello/HelloAIAgents/Program.cs
@@ -24,10 +24,11 @@
 });
 var local = true;
 if (Environment.GetEnvironmentVariable("AGENT_HOST") != null) { local = false; }
-var _ = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
+var app = await Microsoft.AutoGen.Core.Grpc.AgentsApp.PublishMessageAsync("HelloAgents", new NewMessageReceived
 {
     Message = "World"
 }, local: local).ConfigureAwait(false);
+await app.WaitForShutdownAsync();
 
 namespace Hello
 {
diff --git a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
index f73a9a6c71ee..21ec69d42080 100644
--- a/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
+++ b/dotnet/src/Microsoft.AutoGen/Agents/IOAgent/ConsoleAgent/IHandleConsole.cs
@@ -10,7 +10,7 @@ namespace Microsoft.AutoGen.Agents;
 public interface IHandleConsole : IHandle<Output>, IHandle<Input>
 {
     AgentId AgentId { get; }
-    ValueTask PublishMessageAsync<T>(T message, string? topic = null, string? source = null, string? key = null, CancellationToken token = default) where T : IMessage;
+    ValueTask PublishMessageAsync<T>(T message, CancellationToken token = default) where T : IMessage;
 
     async Task IHandle<Output>.Handle(Output item, CancellationToken cancellationToken)
     {

From 8bdffec0988ae6f5b36c5989ba0f7b773a44610b Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 10:54:32 -0800
Subject: [PATCH 056/110] format

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 957ee5828bec..e5e0292556a5 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -290,7 +290,7 @@ static async (state, ct) =>
         return await completion.Task.ConfigureAwait(false);
     }
 
-    private string SetTopic(string? topic = null , string? source = null, string? key = null)
+    private string SetTopic(string? topic = null, string? source = null, string? key = null)
     {
         if (string.IsNullOrWhiteSpace(topic))
         {
@@ -308,7 +308,7 @@ private string SetTopic(string? topic = null , string? source = null, string? ke
     /// <returns>A task representing the asynchronous operation.</returns>
     public async ValueTask PublishMessageAsync<T>(T message, string topic, string source, string key, CancellationToken token = default) where T : IMessage
     {
-        
+
         var topicTypes = this.GetType().GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
         if (!topicTypes.Any())
         {

From 5180dee93a039ab960f613f4c9395da9c8121ea1 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 11:06:48 -0800
Subject: [PATCH 057/110] rename files

---
 ...PrefixSubscription.cs => TypePrefixSubscriptionSurrogate.cs} | 2 +-
 .../{TypeSubscription.cs => TypeSubscriptionSurrogate.cs}       | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
 rename dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/{TypePrefixSubscription.cs => TypePrefixSubscriptionSurrogate.cs} (96%)
 rename dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/{TypeSubscription.cs => TypeSubscriptionSurrogate.cs} (96%)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscriptionSurrogate.cs
similarity index 96%
rename from dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs
rename to dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscriptionSurrogate.cs
index c5427d7bf972..ca4d721315e8 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscription.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypePrefixSubscriptionSurrogate.cs
@@ -1,5 +1,5 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
-// TypePrefixSubscription.cs
+// TypePrefixSubscriptionSurrogate.cs
 
 using Microsoft.AutoGen.Contracts;
 
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscriptionSurrogate.cs
similarity index 96%
rename from dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs
rename to dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscriptionSurrogate.cs
index df38462d044a..57fa202ebfc3 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscription.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/TypeSubscriptionSurrogate.cs
@@ -1,5 +1,5 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
-// TypeSubscription.cs
+// TypeSubscriptionSurrogate.cs
 
 using Microsoft.AutoGen.Contracts;
 

From e26cd1d54b620d21acffe8a2641f942b875b31d3 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 11:17:26 -0800
Subject: [PATCH 058/110] add surrogate for Subscription type

---
 .../Surrogates/SubscriptionSurrogate.cs       | 49 +++++++++++++++++++
 1 file changed, 49 insertions(+)
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs
new file mode 100644
index 000000000000..abf18143929d
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// SubscriptionSurrogate.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct SubscriptionSurrogate
+{
+    [Id(0)]
+    public TypeSubscription? TypeSubscription;
+    [Id(1)]
+    public TypePrefixSubscription? TypePrefixSubscription;
+}
+
+[RegisterConverter]
+public sealed class SubscriptionSurrogateConverter :
+    IConverter<Subscription, SubscriptionSurrogate>
+{
+    public Subscription ConvertFromSurrogate(
+        in SubscriptionSurrogate surrogate)
+    {
+        if (surrogate.TypeSubscription is not null)
+        {
+            return new Subscription
+            {
+                TypeSubscription = surrogate.TypeSubscription
+            };
+        }
+        else
+        {
+            return new Subscription
+            {
+                TypePrefixSubscription = surrogate.TypePrefixSubscription
+            };
+        }
+    }
+
+    public SubscriptionSurrogate ConvertToSurrogate(
+        in Subscription value)
+    {
+        return new SubscriptionSurrogate
+        {
+            TypeSubscription = value.TypeSubscription,
+            TypePrefixSubscription = value.TypePrefixSubscription
+        };
+    }
+}

From 9c7d2bd8b9d473ce52bb34d1f71de35f14d5eaf6 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 19:41:54 -0800
Subject: [PATCH 059/110] Update
 dotnet/samples/Hello/HelloAgentState/Program.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
---
 dotnet/samples/Hello/HelloAgentState/Program.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/samples/Hello/HelloAgentState/Program.cs b/dotnet/samples/Hello/HelloAgentState/Program.cs
index f81ecdad977b..87d39f0461c8 100644
--- a/dotnet/samples/Hello/HelloAgentState/Program.cs
+++ b/dotnet/samples/Hello/HelloAgentState/Program.cs
@@ -29,7 +29,7 @@ public class HelloAgent(
             IHandle<Shutdown>
     {
         private AgentState? State { get; set; }
-        public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
+        var response = await SayHello(item.Message, cancellationToken).ConfigureAwait(false);
         {
             var response = await SayHello(item.Message).ConfigureAwait(false);
             var evt = new Output

From d411001a6ea2e30ea9a6e001d790383efe546ec3 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Mon, 20 Jan 2025 19:45:35 -0800
Subject: [PATCH 060/110] revert dumb copilot change

---
 dotnet/samples/Hello/HelloAgentState/Program.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/samples/Hello/HelloAgentState/Program.cs b/dotnet/samples/Hello/HelloAgentState/Program.cs
index 87d39f0461c8..f81ecdad977b 100644
--- a/dotnet/samples/Hello/HelloAgentState/Program.cs
+++ b/dotnet/samples/Hello/HelloAgentState/Program.cs
@@ -29,7 +29,7 @@ public class HelloAgent(
             IHandle<Shutdown>
     {
         private AgentState? State { get; set; }
-        var response = await SayHello(item.Message, cancellationToken).ConfigureAwait(false);
+        public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
         {
             var response = await SayHello(item.Message).ConfigureAwait(false);
             var evt = new Output

From 76678e87b36dc8c83e154905f43c049e4487165e Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 06:58:19 -0800
Subject: [PATCH 061/110] remove unnecessary inserted using

---
 .../Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs             | 1 -
 1 file changed, 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index fdca333c5534..722b38a3fb21 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -2,7 +2,6 @@
 // GrpcAgentWorkerHostBuilderExtension.cs
 using System.Diagnostics;
 using System.Reflection;
-using Google.Protobuf;
 using Google.Protobuf.Reflection;
 using Grpc.Core;
 using Grpc.Net.Client.Configuration;

From cafb7999364ced9a13928056b9ed1c73bae31834 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 06:59:13 -0800
Subject: [PATCH 062/110] use primary constructor

---
 .../Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs     | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index 18ca0b407a9a..5c33e90e164e 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -7,13 +7,10 @@
 namespace Microsoft.AutoGen.Runtime.Grpc;
 
 // gRPC service which handles communication between the agent worker and the cluster.
-public sealed class GrpcGatewayService : AgentRpc.AgentRpcBase
+public sealed class GrpcGatewayService(GrpcGateway gateway) : AgentRpc.AgentRpcBase
 {
-    private readonly GrpcGateway Gateway;
-    public GrpcGatewayService(GrpcGateway gateway)
-    {
-        Gateway = (GrpcGateway)gateway;
-    }
+    private readonly GrpcGateway Gateway = (GrpcGateway)gateway;
+
     public override async Task OpenChannel(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
     {
         try

From ccfd0cc4f55a4123bf05cea10b52cb5c99e84b6d Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 07:21:38 -0800
Subject: [PATCH 063/110] turning up the logging

---
 dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json       | 3 ++-
 .../test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json   | 4 +++-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json b/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
index f07608ca0aa0..1b15783f8fdd 100644
--- a/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
+++ b/dotnet/src/Microsoft.AutoGen/AgentHost/appsettings.json
@@ -6,7 +6,8 @@
       "Microsoft.AspNetCore": "Information",
       "Microsoft": "Information",
       "Microsoft.Orleans": "Warning",
-      "Orleans.Runtime": "Error"
+      "Orleans.Runtime": "Error",
+      "Grpc": "Information"
     }
   },
   "AllowedHosts": "*",
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json
index ae32fe371a70..3a7561374661 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/appsettings.json
@@ -3,7 +3,9 @@
     "LogLevel": {
       "Default": "Warning",
       "Microsoft": "Warning",
-      "Microsoft.Orleans": "Warning"
+      "Microsoft.Orleans": "Warning",
+      "Orleans.Runtime": "Debug",
+      "Grpc": "Information"
     }
   },
   "AllowedHosts": "*",

From 740047fb0f079cb3e64a44e7a23b4d5131578250 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 08:41:57 -0800
Subject: [PATCH 064/110] add client logging

---
 .../GrpcAgentWorkerHostBuilderExtension.cs    |    3 +-
 python/uv.lock                                | 2325 +----------------
 2 files changed, 99 insertions(+), 2229 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index 722b38a3fb21..e91f7ee28752 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -9,6 +9,7 @@
 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
@@ -21,7 +22,7 @@ public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBu
             options.Address = new Uri(agentServiceAddress ?? builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress);
             options.ChannelOptionsActions.Add(channelOptions =>
             {
-
+                LoggerFactory loggerFactory = new LoggerFactory();
                 channelOptions.HttpHandler = new SocketsHttpHandler
                 {
                     EnableMultipleHttp2Connections = true,
diff --git a/python/uv.lock b/python/uv.lock
index e8a07804e93d..84bfac995e61 100644
--- a/python/uv.lock
+++ b/python/uv.lock
@@ -1,18 +1,42 @@
 version = 1
 requires-python = ">=3.10, <3.13"
 resolution-markers = [
-    "python_full_version >= '3.12.4' and sys_platform == 'darwin'",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform == 'darwin'",
-    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'",
-    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version == '3.11.*' and sys_platform == 'darwin'",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'",
-    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version < '3.11' and sys_platform == 'darwin'",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'",
-    "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'",
+    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
+    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
+    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
+    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
+    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
+    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
+    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
+    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
+    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform == 'darwin'",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
+    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
+    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
+    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform == 'darwin'",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
+    "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
+    "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
+    "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
 ]
 
 [manifest]
@@ -34,29 +58,6 @@ overrides = [
     { name = "tenacity", specifier = ">=9.0.0" },
 ]
 
-[manifest.dependency-groups]
-dev = [
-    { name = "chainlit" },
-    { name = "cookiecutter" },
-    { name = "grpcio-tools", specifier = "~=1.62.0" },
-    { name = "mypy", specifier = "==1.13.0" },
-    { name = "mypy-protobuf" },
-    { name = "packaging" },
-    { name = "poethepoet" },
-    { name = "polars" },
-    { name = "pyright", specifier = "==1.1.389" },
-    { name = "pytest" },
-    { name = "pytest-asyncio" },
-    { name = "pytest-cov" },
-    { name = "pytest-mock" },
-    { name = "pytest-xdist" },
-    { name = "rich" },
-    { name = "ruff", specifier = "==0.4.8" },
-    { name = "tomli" },
-    { name = "tomli-w" },
-    { name = "typer" },
-]
-
 [[package]]
 name = "accelerate"
 version = "1.3.0"
@@ -75,18 +76,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/73/de/64508cb91af013aaba214752309c0967568a4219d50a4ea30e822af3c976/accelerate-1.3.0-py3-none-any.whl", hash = "sha256:5788d9e6a7a9f80fed665cf09681c4dddd9dc056bea656db4140ffc285ce423e", size = 336647 },
 ]
 
-[[package]]
-name = "accessible-pygments"
-version = "0.0.5"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pygments" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903 },
-]
-
 [[package]]
 name = "agbench"
 version = "0.0.1a1"
@@ -101,12 +90,6 @@ dependencies = [
     { name = "tabulate" },
 ]
 
-[package.dev-dependencies]
-dev = [
-    { name = "types-docker" },
-    { name = "types-tabulate" },
-]
-
 [package.metadata]
 requires-dist = [
     { name = "azure-identity" },
@@ -118,12 +101,6 @@ requires-dist = [
     { name = "tabulate" },
 ]
 
-[package.metadata.requires-dev]
-dev = [
-    { name = "types-docker" },
-    { name = "types-tabulate" },
-]
-
 [[package]]
 name = "aiofiles"
 version = "24.1.0"
@@ -149,7 +126,7 @@ source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "aiohappyeyeballs" },
     { name = "aiosignal" },
-    { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+    { name = "async-timeout", marker = "python_full_version < '3.11'" },
     { name = "attrs" },
     { name = "frozenlist" },
     { name = "multidict" },
@@ -205,19 +182,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/7f/23/cc36d9c398980acaeeb443100f0216f50a7cfe20c67a9fd0a2f1a5a846de/aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d", size = 437666 },
 ]
 
-[[package]]
-name = "aiohttp-jinja2"
-version = "1.6"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "jinja2" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/e6/39/da5a94dd89b1af7241fb7fc99ae4e73505b5f898b540b6aba6dc7afe600e/aiohttp-jinja2-1.6.tar.gz", hash = "sha256:a3a7ff5264e5bca52e8ae547bbfd0761b72495230d438d05b6c0915be619b0e2", size = 53057 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/eb/90/65238d4246307195411b87a07d03539049819b022c01bcc773826f600138/aiohttp_jinja2-1.6-py3-none-any.whl", hash = "sha256:0df405ee6ad1b58e5a068a105407dc7dcc1704544c559f1938babde954f945c7", size = 11736 },
-]
-
 [[package]]
 name = "aiolimiter"
 version = "1.2.1"
@@ -239,15 +203,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 },
 ]
 
-[[package]]
-name = "alabaster"
-version = "1.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 },
-]
-
 [[package]]
 name = "alembic"
 version = "1.14.0"
@@ -325,19 +280,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 },
 ]
 
-[[package]]
-name = "arrow"
-version = "1.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "python-dateutil" },
-    { name = "types-python-dateutil" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 },
-]
-
 [[package]]
 name = "asttokens"
 version = "2.4.1"
@@ -354,51 +296,11 @@ wheels = [
 name = "async-timeout"
 version = "4.0.3"
 source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
-    "python_full_version < '3.11' and sys_platform == 'darwin'",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'",
-    "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')",
-]
 sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 }
 wheels = [
     { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 },
 ]
 
-[[package]]
-name = "async-timeout"
-version = "5.0.1"
-source = { registry = "https://pypi.org/simple" }
-resolution-markers = [
-    "python_full_version == '3.11.*' and sys_platform == 'darwin'",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'",
-    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')",
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 },
-]
-
-[[package]]
-name = "asyncer"
-version = "0.0.7"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "anyio" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/39/29/245ba9fa5769a1e3226c1157aedb372fe9dab28c4e1dcf6911d84d3a5e04/asyncer-0.0.7.tar.gz", hash = "sha256:d5e563fb0f56eb87b97257984703658a4f5bbdb52ff851b3e8ed864cc200b1d2", size = 14437 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/3e/4b/40a1dc52fc26695b1e80a9e67dfb0fe7e6ddc57bbc5b61348e40c0045abb/asyncer-0.0.7-py3-none-any.whl", hash = "sha256:f0d579d4f67c4ead52ede3a45c854f462cae569058a8a6a68a4ebccac1c335d8", size = 8476 },
-]
-
-[[package]]
-name = "asyncio-atexit"
-version = "1.0.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/22/d3/dd2974be3f67c7ec96e0d6ab454429d0372cb7c7bffa3d0ac67a483cb801/asyncio-atexit-1.0.1.tar.gz", hash = "sha256:1d0c71544b8ee2c484d322844ee72c0875dde6f250c0ed5b6993592ab9f7d436", size = 4373 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/65/10/d6abaefa57a52646651fd0383c056280b0853c0106229ece6bb38cd14463/asyncio_atexit-1.0.1-py3-none-any.whl", hash = "sha256:d93d5f7d5633a534abd521ce2896ed0fbe8de170bb1e65ec871d1c20eac9d376", size = 3752 },
-]
-
 [[package]]
 name = "attrs"
 version = "24.3.0"
@@ -408,19 +310,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 },
 ]
 
-[[package]]
-name = "autodoc-pydantic"
-version = "2.2.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pydantic" },
-    { name = "pydantic-settings" },
-    { name = "sphinx" },
-]
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7b/df/87120e2195f08d760bc5cf8a31cfa2381a6887517aa89453b23f1ae3354f/autodoc_pydantic-2.2.0-py3-none-any.whl", hash = "sha256:8c6a36fbf6ed2700ea9c6d21ea76ad541b621fbdf16b5a80ee04673548af4d95", size = 34001 },
-]
-
 [[package]]
 name = "autogen-agentchat"
 version = "0.4.3"
@@ -445,54 +334,6 @@ dependencies = [
     { name = "typing-extensions" },
 ]
 
-[package.dev-dependencies]
-dev = [
-    { name = "aiofiles" },
-    { name = "asyncio-atexit" },
-    { name = "autodoc-pydantic" },
-    { name = "autogen-ext" },
-    { name = "autogen-test-utils" },
-    { name = "azure-identity" },
-    { name = "chess" },
-    { name = "colorama" },
-    { name = "diskcache" },
-    { name = "langchain-openai" },
-    { name = "langgraph" },
-    { name = "llama-index" },
-    { name = "llama-index-embeddings-azure-openai" },
-    { name = "llama-index-llms-azure-openai" },
-    { name = "llama-index-readers-web" },
-    { name = "llama-index-readers-wikipedia" },
-    { name = "llama-index-tools-wikipedia" },
-    { name = "markdownify" },
-    { name = "myst-nb" },
-    { name = "nbqa" },
-    { name = "opentelemetry-sdk" },
-    { name = "pip" },
-    { name = "polars" },
-    { name = "pydata-sphinx-theme" },
-    { name = "pygments" },
-    { name = "python-dotenv" },
-    { name = "redis" },
-    { name = "requests" },
-    { name = "sphinx" },
-    { name = "sphinx-autobuild" },
-    { name = "sphinx-copybutton" },
-    { name = "sphinx-design" },
-    { name = "sphinxcontrib-apidoc" },
-    { name = "sphinxext-rediraffe" },
-    { name = "tavily-python" },
-    { name = "textual" },
-    { name = "textual-dev" },
-    { name = "textual-imageview" },
-    { name = "types-aiofiles" },
-    { name = "types-docker" },
-    { name = "types-pillow" },
-    { name = "types-protobuf" },
-    { name = "types-requests" },
-    { name = "wikipedia" },
-]
-
 [package.metadata]
 requires-dist = [
     { name = "jsonref", specifier = "~=1.1.0" },
@@ -503,54 +344,6 @@ requires-dist = [
     { name = "typing-extensions", specifier = ">=4.0.0" },
 ]
 
-[package.metadata.requires-dev]
-dev = [
-    { name = "aiofiles" },
-    { name = "asyncio-atexit" },
-    { name = "autodoc-pydantic", specifier = "~=2.2" },
-    { name = "autogen-ext", editable = "packages/autogen-ext" },
-    { name = "autogen-test-utils", editable = "packages/autogen-test-utils" },
-    { name = "azure-identity" },
-    { name = "chess" },
-    { name = "colorama" },
-    { name = "diskcache" },
-    { name = "langchain-openai" },
-    { name = "langgraph" },
-    { name = "llama-index" },
-    { name = "llama-index-embeddings-azure-openai" },
-    { name = "llama-index-llms-azure-openai" },
-    { name = "llama-index-readers-web" },
-    { name = "llama-index-readers-wikipedia" },
-    { name = "llama-index-tools-wikipedia" },
-    { name = "markdownify" },
-    { name = "myst-nb", specifier = "==1.1.2" },
-    { name = "nbqa" },
-    { name = "opentelemetry-sdk", specifier = ">=1.27.0" },
-    { name = "pip" },
-    { name = "polars" },
-    { name = "pydata-sphinx-theme", specifier = "==0.15.4" },
-    { name = "pygments" },
-    { name = "python-dotenv" },
-    { name = "redis" },
-    { name = "requests" },
-    { name = "sphinx" },
-    { name = "sphinx-autobuild" },
-    { name = "sphinx-copybutton" },
-    { name = "sphinx-design" },
-    { name = "sphinxcontrib-apidoc" },
-    { name = "sphinxext-rediraffe" },
-    { name = "tavily-python" },
-    { name = "textual" },
-    { name = "textual-dev" },
-    { name = "textual-imageview" },
-    { name = "types-aiofiles" },
-    { name = "types-docker" },
-    { name = "types-pillow" },
-    { name = "types-protobuf" },
-    { name = "types-requests" },
-    { name = "wikipedia" },
-]
-
 [[package]]
 name = "autogen-ext"
 version = "0.4.3"
@@ -647,13 +440,6 @@ web-surfer = [
     { name = "playwright" },
 ]
 
-[package.dev-dependencies]
-dev = [
-    { name = "autogen-test-utils" },
-    { name = "langchain-experimental" },
-    { name = "pandas-stubs" },
-]
-
 [package.metadata]
 requires-dist = [
     { name = "aiofiles", marker = "extra == 'openai'" },
@@ -697,13 +483,6 @@ requires-dist = [
     { name = "tiktoken", marker = "extra == 'openai'", specifier = ">=0.8.0" },
 ]
 
-[package.metadata.requires-dev]
-dev = [
-    { name = "autogen-test-utils", editable = "packages/autogen-test-utils" },
-    { name = "langchain-experimental" },
-    { name = "pandas-stubs", specifier = ">=2.2.3.241126" },
-]
-
 [[package]]
 name = "autogen-magentic-one"
 version = "0.0.1"
@@ -730,16 +509,6 @@ dependencies = [
     { name = "youtube-transcript-api" },
 ]
 
-[package.dev-dependencies]
-dev = [
-    { name = "aiofiles" },
-    { name = "azure-identity" },
-    { name = "openpyxl" },
-    { name = "types-aiofiles" },
-    { name = "types-pillow" },
-    { name = "types-requests" },
-]
-
 [package.metadata]
 requires-dist = [
     { name = "aiofiles" },
@@ -763,16 +532,6 @@ requires-dist = [
     { name = "youtube-transcript-api" },
 ]
 
-[package.metadata.requires-dev]
-dev = [
-    { name = "aiofiles" },
-    { name = "azure-identity" },
-    { name = "openpyxl" },
-    { name = "types-aiofiles" },
-    { name = "types-pillow" },
-    { name = "types-requests" },
-]
-
 [[package]]
 name = "autogen-test-utils"
 version = "0.0.0"
@@ -861,19 +620,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/6d/90/d13cf396989052cadd8511c1878b0913bbce28eeef5feb95710a92e03076/autograd-1.7.0-py3-none-any.whl", hash = "sha256:49680300f842f3a8722b060ac0d3ed7aca071d1ad4d3d38c9fdadafdcc73c30b", size = 52522 },
 ]
 
-[[package]]
-name = "autopep8"
-version = "2.3.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pycodestyle" },
-    { name = "tomli", marker = "python_full_version < '3.11'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/50/d8/30873d2b7b57dee9263e53d142da044c4600a46f2d28374b3e38b023df16/autopep8-2.3.2.tar.gz", hash = "sha256:89440a4f969197b69a995e4ce0661b031f455a9f776d2c5ba3dbd83466931758", size = 92210 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl", hash = "sha256:ce8ad498672c845a0c3de2629c15b635ec2b05ef8177a6e7c91c74f3e9b51128", size = 45807 },
-]
-
 [[package]]
 name = "azure-common"
 version = "1.1.28"
@@ -956,15 +702,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/e2/f8/ef0f76f8c424bedd20c685409836ddfb42ac76fd8a0f21c3c3659cf7207d/azure_storage_blob-12.24.0-py3-none-any.whl", hash = "sha256:4f0bb4592ea79a2d986063696514c781c9e62be240f09f6397986e01755bc071", size = 408579 },
 ]
 
-[[package]]
-name = "babel"
-version = "2.16.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 },
-]
-
 [[package]]
 name = "beartype"
 version = "0.18.5"
@@ -986,27 +723,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 },
 ]
 
-[[package]]
-name = "bidict"
-version = "0.23.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764 },
-]
-
-[[package]]
-name = "binaryornot"
-version = "0.4.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "chardet" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a7/fe/7ebfec74d49f97fc55cd38240c7a7d08134002b1e14be8c3897c0dd5e49b/binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", size = 371054 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4", size = 9006 },
-]
-
 [[package]]
 name = "blinker"
 version = "1.9.0"
@@ -1108,39 +824,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
 ]
 
-[[package]]
-name = "chainlit"
-version = "2.0.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiofiles" },
-    { name = "asyncer" },
-    { name = "click" },
-    { name = "dataclasses-json" },
-    { name = "fastapi" },
-    { name = "filetype" },
-    { name = "httpx" },
-    { name = "lazify" },
-    { name = "literalai" },
-    { name = "nest-asyncio" },
-    { name = "packaging" },
-    { name = "pydantic" },
-    { name = "pyjwt" },
-    { name = "python-dotenv" },
-    { name = "python-multipart" },
-    { name = "python-socketio" },
-    { name = "starlette" },
-    { name = "syncer" },
-    { name = "tomli" },
-    { name = "uptrace" },
-    { name = "uvicorn" },
-    { name = "watchfiles" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/e0/15/26dc5f957c6344813b2ae8c6f52cc820a7074088509ea947da0cf76ffc5f/chainlit-2.0.1.tar.gz", hash = "sha256:9fb7728aa5704e823c5b5d51f570dcfabafdcc97c23a73e6047f65eb72c938e7", size = 4637433 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ca/99/c63fa2e1d7b949c034b7fc838a0c00de22cd2cec30245e379c9dd15dedfd/chainlit-2.0.1-py3-none-any.whl", hash = "sha256:84982902c6f42a91ac341ea9b6d52e6b1348e53a60ee49b4ffe0e5e5be02f4ba", size = 4703745 },
-]
-
 [[package]]
 name = "chardet"
 version = "5.2.0"
@@ -1198,39 +881,12 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 },
 ]
 
-[[package]]
-name = "chess"
-version = "1.11.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/74/16/53b895bb4fccede8e506de820fa94db03a2dc8bd2ca4bec0aac4a112fb65/chess-1.11.1.tar.gz", hash = "sha256:b7f66a32dc599ab260e2b688e6ac4e868dad840377a54b61357e2dec2a5fed00", size = 156529 }
-
-[[package]]
-name = "chevron"
-version = "0.14.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/15/1f/ca74b65b19798895d63a6e92874162f44233467c9e7c1ed8afd19016ebe9/chevron-0.14.0.tar.gz", hash = "sha256:87613aafdf6d77b6a90ff073165a61ae5086e21ad49057aa0e53681601800ebf", size = 11440 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/52/93/342cc62a70ab727e093ed98e02a725d85b746345f05d2b5e5034649f4ec8/chevron-0.14.0-py3-none-any.whl", hash = "sha256:fbf996a709f8da2e745ef763f482ce2d311aa817d287593a5b990d6d6e4f0443", size = 11595 },
-]
-
-[[package]]
-name = "chromedriver-autoinstaller"
-version = "0.6.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "packaging" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/d0/5a/9fc60c65673444d592b8922316c3abcd6177b42208c5a6179f96ccf0e11b/chromedriver-autoinstaller-0.6.4.tar.gz", hash = "sha256:1b4df04b87e6107c730085b98e5fd541db3d1777c32b8bd08e2ca4b1244050af", size = 6944 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a5/b5/36f0b0add145c371b5282e881a687601899f2d27fae5d0595bc02026b67c/chromedriver_autoinstaller-0.6.4-py3-none-any.whl", hash = "sha256:b12ed187ca9fac4d744deb588d221222ed50836384607e5303e6eab98bb9dc64", size = 7634 },
-]
-
 [[package]]
 name = "click"
 version = "8.1.8"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "colorama", marker = "platform_system == 'Windows'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
 wheels = [
@@ -1350,69 +1006,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/52/94/86bfae441707205634d80392e873295652fc313dfd93c233c52c4dc07874/contourpy-1.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53", size = 218221 },
 ]
 
-[[package]]
-name = "cookiecutter"
-version = "2.6.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "arrow" },
-    { name = "binaryornot" },
-    { name = "click" },
-    { name = "jinja2" },
-    { name = "python-slugify" },
-    { name = "pyyaml" },
-    { name = "requests" },
-    { name = "rich" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/52/17/9f2cd228eb949a91915acd38d3eecdc9d8893dde353b603f0db7e9f6be55/cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c", size = 158767 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d", size = 39177 },
-]
-
-[[package]]
-name = "coverage"
-version = "7.6.10"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/c5/12/2a2a923edf4ddabdffed7ad6da50d96a5c126dae7b80a33df7310e329a1e/coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", size = 207982 },
-    { url = "https://files.pythonhosted.org/packages/ca/49/6985dbca9c7be3f3cb62a2e6e492a0c88b65bf40579e16c71ae9c33c6b23/coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", size = 208414 },
-    { url = "https://files.pythonhosted.org/packages/35/93/287e8f1d1ed2646f4e0b2605d14616c9a8a2697d0d1b453815eb5c6cebdb/coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", size = 236860 },
-    { url = "https://files.pythonhosted.org/packages/de/e1/cfdb5627a03567a10031acc629b75d45a4ca1616e54f7133ca1fa366050a/coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", size = 234758 },
-    { url = "https://files.pythonhosted.org/packages/6d/85/fc0de2bcda3f97c2ee9fe8568f7d48f7279e91068958e5b2cc19e0e5f600/coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", size = 235920 },
-    { url = "https://files.pythonhosted.org/packages/79/73/ef4ea0105531506a6f4cf4ba571a214b14a884630b567ed65b3d9c1975e1/coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", size = 234986 },
-    { url = "https://files.pythonhosted.org/packages/c6/4d/75afcfe4432e2ad0405c6f27adeb109ff8976c5e636af8604f94f29fa3fc/coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", size = 233446 },
-    { url = "https://files.pythonhosted.org/packages/86/5b/efee56a89c16171288cafff022e8af44f8f94075c2d8da563c3935212871/coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", size = 234566 },
-    { url = "https://files.pythonhosted.org/packages/f2/db/67770cceb4a64d3198bf2aa49946f411b85ec6b0a9b489e61c8467a4253b/coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", size = 210675 },
-    { url = "https://files.pythonhosted.org/packages/8d/27/e8bfc43f5345ec2c27bc8a1fa77cdc5ce9dcf954445e11f14bb70b889d14/coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", size = 211518 },
-    { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088 },
-    { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536 },
-    { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 },
-    { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 },
-    { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 },
-    { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 },
-    { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 },
-    { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 },
-    { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647 },
-    { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508 },
-    { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 },
-    { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 },
-    { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 },
-    { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 },
-    { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 },
-    { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 },
-    { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 },
-    { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 },
-    { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 },
-    { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 },
-    { url = "https://files.pythonhosted.org/packages/a1/70/de81bfec9ed38a64fc44a77c7665e20ca507fc3265597c28b0d989e4082e/coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f", size = 200223 },
-]
-
-[package.optional-dependencies]
-toml = [
-    { name = "tomli", marker = "python_full_version <= '3.11'" },
-]
-
 [[package]]
 name = "cryptography"
 version = "44.0.0"
@@ -1450,15 +1043,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/cc/9d/37e5da7519de7b0b070a3fedd4230fe76d50d2a21403e0f2153d70ac4163/cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", size = 3128774 },
 ]
 
-[[package]]
-name = "cssselect"
-version = "1.2.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d1/91/d51202cc41fbfca7fa332f43a5adac4b253962588c7cc5a54824b019081c/cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc", size = 41423 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/06/a9/2da08717a6862c48f1d61ef957a7bba171e7eefa6c0aa0ceb96a140c2a6b/cssselect-1.2.0-py2.py3-none-any.whl", hash = "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e", size = 18687 },
-]
-
 [[package]]
 name = "cycler"
 version = "0.12.1"
@@ -1499,19 +1083,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/aa/3f/94cff4e36962b843a78a831770b9b44e476a5f9c76c0d53f7cf92053a1b4/dapr_ext_fastapi-1.14.0-py3-none-any.whl", hash = "sha256:88df67d6af33fd5adcf97d8799fa43373774b13cb9a1091ac4dd47e18a009ca0", size = 10458 },
 ]
 
-[[package]]
-name = "dataclasses-json"
-version = "0.6.7"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "marshmallow" },
-    { name = "typing-inspect" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686 },
-]
-
 [[package]]
 name = "debugpy"
 version = "1.8.11"
@@ -1589,15 +1160,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d1/ae/afb1487556e2dc827a17097aac8158a25b433a345386f0e249f6d2694ccb/devtools-0.12.2-py3-none-any.whl", hash = "sha256:c366e3de1df4cdd635f1ad8cbcd3af01a384d7abda71900e68d43b04eb6aaca7", size = 19411 },
 ]
 
-[[package]]
-name = "dirtyjson"
-version = "1.0.8"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/db/04/d24f6e645ad82ba0ef092fa17d9ef7a21953781663648a01c9371d9e8e98/dirtyjson-1.0.8.tar.gz", hash = "sha256:90ca4a18f3ff30ce849d100dcf4a003953c79d3a2348ef056f1d9c22231a25fd", size = 30782 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/68/69/1bcf70f81de1b4a9f21b3a62ec0c83bdff991c88d6cc2267d02408457e88/dirtyjson-1.0.8-py3-none-any.whl", hash = "sha256:125e27248435a58acace26d5c2c4c11a1c0de0a9c5124c5a94ba78e517d74f53", size = 25197 },
-]
-
 [[package]]
 name = "diskcache"
 version = "5.6.3"
@@ -1639,15 +1201,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533 },
 ]
 
-[[package]]
-name = "docutils"
-version = "0.21.2"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 },
-]
-
 [[package]]
 name = "environs"
 version = "11.2.1"
@@ -1688,15 +1241,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
 ]
 
-[[package]]
-name = "execnet"
-version = "2.1.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612 },
-]
-
 [[package]]
 name = "executing"
 version = "2.1.0"
@@ -1729,29 +1273,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 },
 ]
 
-[[package]]
-name = "feedfinder2"
-version = "0.0.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "beautifulsoup4" },
-    { name = "requests" },
-    { name = "six" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/35/82/1251fefec3bb4b03fd966c7e7f7a41c9fc2bb00d823a34c13f847fd61406/feedfinder2-0.0.4.tar.gz", hash = "sha256:3701ee01a6c85f8b865a049c30ba0b4608858c803fe8e30d1d289fdbe89d0efe", size = 3297 }
-
-[[package]]
-name = "feedparser"
-version = "6.0.11"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "sgmllib3k" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ff/aa/7af346ebeb42a76bf108027fe7f3328bb4e57a3a96e53e21fd9ef9dd6dd0/feedparser-6.0.11.tar.gz", hash = "sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5", size = 286197 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7c/d4/8c31aad9cc18f451c49f7f9cfb5799dadffc88177f7917bc90a66459b1d7/feedparser-6.0.11-py3-none-any.whl", hash = "sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45", size = 81343 },
-]
-
 [[package]]
 name = "ffmpeg-python"
 version = "0.2.0"
@@ -1773,15 +1294,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 },
 ]
 
-[[package]]
-name = "filetype"
-version = "1.2.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970 },
-]
-
 [[package]]
 name = "flask"
 version = "3.1.0"
@@ -2385,43 +1897,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/90/40/972271de05f9315c0d69f9f7ebbcadd83bc85322f538637d11bb8c67803d/grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8", size = 14448 },
 ]
 
-[[package]]
-name = "grpcio-tools"
-version = "1.62.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "grpcio" },
-    { name = "protobuf" },
-    { name = "setuptools" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/54/fa/b69bd8040eafc09b88bb0ec0fea59e8aacd1a801e688af087cead213b0d0/grpcio-tools-1.62.3.tar.gz", hash = "sha256:7c7136015c3d62c3eef493efabaf9e3380e3e66d24ee8e94c01cb71377f57833", size = 4538520 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ff/eb/eb0a3aa9480c3689d31fd2ad536df6a828e97a60f667c8a93d05bdf07150/grpcio_tools-1.62.3-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2f968b049c2849540751ec2100ab05e8086c24bead769ca734fdab58698408c1", size = 5117556 },
-    { url = "https://files.pythonhosted.org/packages/f3/fb/8be3dda485f7fab906bfa02db321c3ecef953a87cdb5f6572ca08b187bcb/grpcio_tools-1.62.3-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:0a8c0c4724ae9c2181b7dbc9b186df46e4f62cb18dc184e46d06c0ebeccf569e", size = 2719330 },
-    { url = "https://files.pythonhosted.org/packages/63/de/6978f8d10066e240141cd63d1fbfc92818d96bb53427074f47a8eda921e1/grpcio_tools-1.62.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5782883a27d3fae8c425b29a9d3dcf5f47d992848a1b76970da3b5a28d424b26", size = 3070818 },
-    { url = "https://files.pythonhosted.org/packages/74/34/bb8f816893fc73fd6d830e895e8638d65d13642bb7a434f9175c5ca7da11/grpcio_tools-1.62.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d812daffd0c2d2794756bd45a353f89e55dc8f91eb2fc840c51b9f6be62667", size = 2804993 },
-    { url = "https://files.pythonhosted.org/packages/78/60/b2198d7db83293cdb9760fc083f077c73e4c182da06433b3b157a1567d06/grpcio_tools-1.62.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b47d0dda1bdb0a0ba7a9a6de88e5a1ed61f07fad613964879954961e36d49193", size = 3684915 },
-    { url = "https://files.pythonhosted.org/packages/61/20/56dbdc4ecb14d42a03cd164ff45e6e84572bbe61ee59c50c39f4d556a8d5/grpcio_tools-1.62.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ca246dffeca0498be9b4e1ee169b62e64694b0f92e6d0be2573e65522f39eea9", size = 3297482 },
-    { url = "https://files.pythonhosted.org/packages/4a/dc/e417a313c905744ce8cedf1e1edd81c41dc45ff400ae1c45080e18f26712/grpcio_tools-1.62.3-cp310-cp310-win32.whl", hash = "sha256:6a56d344b0bab30bf342a67e33d386b0b3c4e65868ffe93c341c51e1a8853ca5", size = 909793 },
-    { url = "https://files.pythonhosted.org/packages/d9/69/75e7ebfd8d755d3e7be5c6d1aa6d13220f5bba3a98965e4b50c329046777/grpcio_tools-1.62.3-cp310-cp310-win_amd64.whl", hash = "sha256:710fecf6a171dcbfa263a0a3e7070e0df65ba73158d4c539cec50978f11dad5d", size = 1052459 },
-    { url = "https://files.pythonhosted.org/packages/23/52/2dfe0a46b63f5ebcd976570aa5fc62f793d5a8b169e211c6a5aede72b7ae/grpcio_tools-1.62.3-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:703f46e0012af83a36082b5f30341113474ed0d91e36640da713355cd0ea5d23", size = 5147623 },
-    { url = "https://files.pythonhosted.org/packages/f0/2e/29fdc6c034e058482e054b4a3c2432f84ff2e2765c1342d4f0aa8a5c5b9a/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7cc83023acd8bc72cf74c2edbe85b52098501d5b74d8377bfa06f3e929803492", size = 2719538 },
-    { url = "https://files.pythonhosted.org/packages/f9/60/abe5deba32d9ec2c76cdf1a2f34e404c50787074a2fee6169568986273f1/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ff7d58a45b75df67d25f8f144936a3e44aabd91afec833ee06826bd02b7fbe7", size = 3070964 },
-    { url = "https://files.pythonhosted.org/packages/bc/ad/e2b066684c75f8d9a48508cde080a3a36618064b9cadac16d019ca511444/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f2483ea232bd72d98a6dc6d7aefd97e5bc80b15cd909b9e356d6f3e326b6e43", size = 2805003 },
-    { url = "https://files.pythonhosted.org/packages/9c/3f/59bf7af786eae3f9d24ee05ce75318b87f541d0950190ecb5ffb776a1a58/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:962c84b4da0f3b14b3cdb10bc3837ebc5f136b67d919aea8d7bb3fd3df39528a", size = 3685154 },
-    { url = "https://files.pythonhosted.org/packages/f1/79/4dd62478b91e27084c67b35a2316ce8a967bd8b6cb8d6ed6c86c3a0df7cb/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ad0473af5544f89fc5a1ece8676dd03bdf160fb3230f967e05d0f4bf89620e3", size = 3297942 },
-    { url = "https://files.pythonhosted.org/packages/b8/cb/86449ecc58bea056b52c0b891f26977afc8c4464d88c738f9648da941a75/grpcio_tools-1.62.3-cp311-cp311-win32.whl", hash = "sha256:db3bc9fa39afc5e4e2767da4459df82b095ef0cab2f257707be06c44a1c2c3e5", size = 910231 },
-    { url = "https://files.pythonhosted.org/packages/45/a4/9736215e3945c30ab6843280b0c6e1bff502910156ea2414cd77fbf1738c/grpcio_tools-1.62.3-cp311-cp311-win_amd64.whl", hash = "sha256:e0898d412a434e768a0c7e365acabe13ff1558b767e400936e26b5b6ed1ee51f", size = 1052496 },
-    { url = "https://files.pythonhosted.org/packages/2a/a5/d6887eba415ce318ae5005e8dfac3fa74892400b54b6d37b79e8b4f14f5e/grpcio_tools-1.62.3-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d102b9b21c4e1e40af9a2ab3c6d41afba6bd29c0aa50ca013bf85c99cdc44ac5", size = 5147690 },
-    { url = "https://files.pythonhosted.org/packages/8a/7c/3cde447a045e83ceb4b570af8afe67ffc86896a2fe7f59594dc8e5d0a645/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0a52cc9444df978438b8d2332c0ca99000521895229934a59f94f37ed896b133", size = 2720538 },
-    { url = "https://files.pythonhosted.org/packages/88/07/f83f2750d44ac4f06c07c37395b9c1383ef5c994745f73c6bfaf767f0944/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141d028bf5762d4a97f981c501da873589df3f7e02f4c1260e1921e565b376fa", size = 3071571 },
-    { url = "https://files.pythonhosted.org/packages/37/74/40175897deb61e54aca716bc2e8919155b48f33aafec8043dda9592d8768/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47a5c093ab256dec5714a7a345f8cc89315cb57c298b276fa244f37a0ba507f0", size = 2806207 },
-    { url = "https://files.pythonhosted.org/packages/ec/ee/d8de915105a217cbcb9084d684abdc032030dcd887277f2ef167372287fe/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f6831fdec2b853c9daa3358535c55eed3694325889aa714070528cf8f92d7d6d", size = 3685815 },
-    { url = "https://files.pythonhosted.org/packages/fd/d9/4360a6c12be3d7521b0b8c39e5d3801d622fbb81cc2721dbd3eee31e28c8/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e02d7c1a02e3814c94ba0cfe43d93e872c758bd8fd5c2797f894d0c49b4a1dfc", size = 3298378 },
-    { url = "https://files.pythonhosted.org/packages/29/3b/7cdf4a9e5a3e0a35a528b48b111355cd14da601413a4f887aa99b6da468f/grpcio_tools-1.62.3-cp312-cp312-win32.whl", hash = "sha256:b881fd9505a84457e9f7e99362eeedd86497b659030cf57c6f0070df6d9c2b9b", size = 910416 },
-    { url = "https://files.pythonhosted.org/packages/6c/66/dd3ec249e44c1cc15e902e783747819ed41ead1336fcba72bf841f72c6e9/grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl", hash = "sha256:11c625eebefd1fd40a228fc8bae385e448c7e32a6ae134e43cf13bbc23f902b7", size = 1052856 },
-]
-
 [[package]]
 name = "h11"
 version = "0.14.0"
@@ -2431,12 +1906,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
 ]
 
-[[package]]
-name = "html2text"
-version = "2024.2.26"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/1a/43/e1d53588561e533212117750ee79ad0ba02a41f52a08c1df3396bd466c05/html2text-2024.2.26.tar.gz", hash = "sha256:05f8e367d15aaabc96415376776cdd11afd5127a77fce6e36afc60c563ca2c32", size = 56527 }
-
 [[package]]
 name = "httpcore"
 version = "1.0.7"
@@ -2478,17 +1947,8 @@ wheels = [
 ]
 
 [[package]]
-name = "httpx-sse"
-version = "0.4.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
-]
-
-[[package]]
-name = "huggingface-hub"
-version = "0.27.1"
+name = "huggingface-hub"
+version = "0.27.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "filelock" },
@@ -2540,15 +2000,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
 ]
 
-[[package]]
-name = "imagesize"
-version = "1.4.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 },
-]
-
 [[package]]
 name = "importlib-metadata"
 version = "8.4.0"
@@ -2575,7 +2026,7 @@ name = "ipykernel"
 version = "6.29.5"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "appnope", marker = "sys_platform == 'darwin'" },
+    { name = "appnope", marker = "platform_system == 'Darwin'" },
     { name = "comm" },
     { name = "debugpy" },
     { name = "ipython" },
@@ -2646,12 +2097,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 },
 ]
 
-[[package]]
-name = "jieba3k"
-version = "0.35.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a9/cb/2c8332bcdc14d33b0bedd18ae0a4981a069c3513e445120da3c3f23a8aaa/jieba3k-0.35.1.zip", hash = "sha256:980a4f2636b778d312518066be90c7697d410dd5a472385f5afced71a2db1c10", size = 7423646 }
-
 [[package]]
 name = "jinja2"
 version = "3.1.5"
@@ -2816,25 +2261,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 },
 ]
 
-[[package]]
-name = "jupyter-cache"
-version = "1.0.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "attrs" },
-    { name = "click" },
-    { name = "importlib-metadata" },
-    { name = "nbclient" },
-    { name = "nbformat" },
-    { name = "pyyaml" },
-    { name = "sqlalchemy" },
-    { name = "tabulate" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907 },
-]
-
 [[package]]
 name = "jupyter-client"
 version = "8.6.3"
@@ -2945,51 +2371,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/34/b9/a3d4bfdaefbc9098ef18bff2cf403c6060f70894c5022983464f9c3db367/lancedb-0.17.0-cp39-abi3-win_amd64.whl", hash = "sha256:9d7e82f83f430d906c285d3303729258b21b1cc8da634c9f7017e354bcb7318a", size = 27511050 },
 ]
 
-[[package]]
-name = "langchain"
-version = "0.3.14"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
-    { name = "langchain-core" },
-    { name = "langchain-text-splitters" },
-    { name = "langsmith" },
-    { name = "numpy" },
-    { name = "pydantic" },
-    { name = "pyyaml" },
-    { name = "requests" },
-    { name = "sqlalchemy" },
-    { name = "tenacity" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/18/35/2adb0693acc149e462bc0e7856ecd58096c285f66a78bc44fc2b8ae91ce0/langchain-0.3.14.tar.gz", hash = "sha256:4a5ae817b5832fa0e1fcadc5353fbf74bebd2f8e550294d4dc039f651ddcd3d1", size = 420409 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d0/a8/0a8f868615b7a30636b1d15b718e3ea9875bf0dccced03583477c2372495/langchain-0.3.14-py3-none-any.whl", hash = "sha256:5df9031702f7fe6c956e84256b4639a46d5d03a75be1ca4c1bc9479b358061a2", size = 1009213 },
-]
-
-[[package]]
-name = "langchain-community"
-version = "0.3.14"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "dataclasses-json" },
-    { name = "httpx-sse" },
-    { name = "langchain" },
-    { name = "langchain-core" },
-    { name = "langsmith" },
-    { name = "numpy" },
-    { name = "pydantic-settings" },
-    { name = "pyyaml" },
-    { name = "requests" },
-    { name = "sqlalchemy" },
-    { name = "tenacity" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/a32cddaa9e8c618e69cfbfdb11cb8718bd9a531ae8426f6a2125a7a5d31f/langchain_community-0.3.14.tar.gz", hash = "sha256:d8ba0fe2dbb5795bff707684b712baa5ee379227194610af415ccdfdefda0479", size = 1720031 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7b/df/3a226f47aad50605a4ff77a30e876d7520f2060aa624532872e44ea048d8/langchain_community-0.3.14-py3-none-any.whl", hash = "sha256:cc02a0abad0551edef3e565dff643386a5b2ee45b933b6d883d4a935b9649f3c", size = 2502417 },
-]
-
 [[package]]
 name = "langchain-core"
 version = "0.3.29"
@@ -3008,85 +2389,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/95/4f/fe1de63f6fc1ac7af3ba4ae12d420af1a19f7893b5fcb72856b9fc67f650/langchain_core-0.3.29-py3-none-any.whl", hash = "sha256:817db1474871611a81105594a3e4d11704949661008e455a10e38ca9ff601a1a", size = 411593 },
 ]
 
-[[package]]
-name = "langchain-experimental"
-version = "0.3.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "langchain-community" },
-    { name = "langchain-core" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/27/56/a8acbb08a03383c28875b3b151e4cefea5612266917fbd6fc3c14c21e172/langchain_experimental-0.3.4.tar.gz", hash = "sha256:937c4259ee4a639c618d19acf0e2c5c2898ef127050346edc5655259aa281a21", size = 140532 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/b2/27/fe8caa4884611286b1f7d6c5cfd76e1fef188faaa946db4fde6daa1cd2cd/langchain_experimental-0.3.4-py3-none-any.whl", hash = "sha256:2e587306aea36b60fa5e5fc05dc7281bee9f60a806f0bf9d30916e0ee096af80", size = 209154 },
-]
-
-[[package]]
-name = "langchain-openai"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "langchain-core" },
-    { name = "openai" },
-    { name = "tiktoken" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/16/0a/0711117a4e8273d5edd4899399a8597d848b2d7b3c9ba3be97038b4fbc1a/langchain_openai-0.3.0.tar.gz", hash = "sha256:88d623eeb2aaa1fff65c2b419a4a1cfd37d3a1d504e598b87cf0bc822a3b70d0", size = 48067 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/4a/9c/b38e308ac668f6db067b424a2a78e5b865753c144a119456f008a09230db/langchain_openai-0.3.0-py3-none-any.whl", hash = "sha256:49c921a22d272b04749a61e78bffa83aecdb8840b24b69f2909e115a357a9a5b", size = 54218 },
-]
-
-[[package]]
-name = "langchain-text-splitters"
-version = "0.3.5"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "langchain-core" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/10/35/a6f8d6b1bb0e6e8c00b49bce4d1a115f8b68368b1899f65bb34dbbb44160/langchain_text_splitters-0.3.5.tar.gz", hash = "sha256:11cb7ca3694e5bdd342bc16d3875b7f7381651d4a53cbb91d34f22412ae16443", size = 26318 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/4b/83/f8081c3bea416bd9d9f0c26af795c74f42c24f9ad3c4fbf361b7d69de134/langchain_text_splitters-0.3.5-py3-none-any.whl", hash = "sha256:8c9b059827438c5fa8f327b4df857e307828a5ec815163c9b5c9569a3e82c8ee", size = 31620 },
-]
-
-[[package]]
-name = "langgraph"
-version = "0.2.62"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "langchain-core" },
-    { name = "langgraph-checkpoint" },
-    { name = "langgraph-sdk" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/54/bb/23859e3c219944bc9f1f3093629970631b3a6dc0aeaf607d7d205b2b551e/langgraph-0.2.62.tar.gz", hash = "sha256:0aac9fd55ffe669bc1312203e0f9ea2733c65cc276f196e7ff0d443cf4efbb89", size = 119343 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/30/38/571f8bc14d4ced8e9d86aca657ffd9a6d076e32e2a62d487eab15f2ceca7/langgraph-0.2.62-py3-none-any.whl", hash = "sha256:51ae9e02a52485a837642eebe7ae43269af7d7305d62f8f69ac11589b2fbba26", size = 138170 },
-]
-
-[[package]]
-name = "langgraph-checkpoint"
-version = "2.0.10"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "langchain-core" },
-    { name = "msgpack" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/26/96/378e06c60d8c8cf44e1d6a2b669e9d5d87236bdee6bf7cfc9125ef5b5d0e/langgraph_checkpoint-2.0.10.tar.gz", hash = "sha256:2dcc04e09091d588bb6209e49d83ff5406d7231c2590d6ff18fb29ab8b140129", size = 33431 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/4d/ef/c320b52035e29081f2693377602289a00545016b4adcc963d5e202ac0c92/langgraph_checkpoint-2.0.10-py3-none-any.whl", hash = "sha256:0d592cfda2df93844c6ea44d142170a8f7e5ba5320274e0e5e60e27f2749392c", size = 37476 },
-]
-
-[[package]]
-name = "langgraph-sdk"
-version = "0.1.51"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "httpx" },
-    { name = "orjson" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/32/d1/95ae599428e8e7d90229e402adf3056072f2ebd0c45c7f7154a5243ff35a/langgraph_sdk-0.1.51.tar.gz", hash = "sha256:dea1363e72562cb1e82a2d156be8d5b1a69ff3fe8815eee0e1e7a2f423242ec1", size = 41591 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/86/e9/d5d2ea883ddb3e16d4c18213457b3f3d04380089d410db71faae52a3c34a/langgraph_sdk-0.1.51-py3-none-any.whl", hash = "sha256:ce2b58466d1700d06149782ed113157a8694a6d7932c801f316cd13fab315fe4", size = 44652 },
-]
-
 [[package]]
 name = "langsmith"
 version = "0.2.10"
@@ -3103,15 +2405,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/12/91/e72d13f6b57a0ea9d884ab1d3388f544d7fe3354dbe1d4dd67678693a9fd/langsmith-0.2.10-py3-none-any.whl", hash = "sha256:b02f2f174189ff72e54c88b1aa63343defd6f0f676c396a690c63a4b6495dcc2", size = 326432 },
 ]
 
-[[package]]
-name = "lazify"
-version = "0.4.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/24/2c/b55c4a27a56dd9a00bb2812c404b57f8b7aec0cdbff9fdc61acdd73359bc/Lazify-0.4.0.tar.gz", hash = "sha256:7102bfe63e56de2ab62b3bc661a7190c4056771a8624f04a8b785275c3dd1f9b", size = 2968 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/03/a5/866b44697cee47d1cae429ed370281d937ad4439f71af82a6baaa139d26a/Lazify-0.4.0-py2.py3-none-any.whl", hash = "sha256:c2c17a7a33e9406897e3f66fde4cd3f84716218d580330e5af10cfe5a0cd195a", size = 3107 },
-]
-
 [[package]]
 name = "lazy-object-proxy"
 version = "1.10.0"
@@ -3142,327 +2435,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/31/8b/94dc8d58704ab87b39faed6f2fc0090b9d90e2e2aa2bbec35c79f3d2a054/lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d", size = 16405 },
 ]
 
-[[package]]
-name = "linkify-it-py"
-version = "2.0.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "uc-micro-py" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820 },
-]
-
-[[package]]
-name = "literalai"
-version = "0.0.623"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "chevron" },
-    { name = "httpx" },
-    { name = "packaging" },
-    { name = "pydantic" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/41/af/07d943e62a1297a7b44777297c0dca8f4bfcd6ae18b9df7d3cd9c1970e29/literalai-0.0.623.tar.gz", hash = "sha256:d65c04dde6b1e99d585e4112a607e5fd574d282b70f600c55a671018340dfb0f", size = 57081 }
-
-[[package]]
-name = "llama-cloud"
-version = "0.1.8"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "certifi" },
-    { name = "httpx" },
-    { name = "pydantic" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a0/e8/6dcc69cd624f3267e41e2077f33f98c27727a9842a5d8244ce6cf0671859/llama_cloud-0.1.8.tar.gz", hash = "sha256:7199bab2240a9cc330740003fa77648f43f6e533da411a8250a4a70584f91153", size = 90827 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/99/0f/af106de1780cf526c96de1ba279edcb55a0376a4484a7dea206f9f038cc4/llama_cloud-0.1.8-py3-none-any.whl", hash = "sha256:1a0c4cf212a04f2375f1d0791ca4e5f196e0fb0567c4ec96cd9dbcad773de60a", size = 247083 },
-]
-
-[[package]]
-name = "llama-index"
-version = "0.12.11"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-agent-openai" },
-    { name = "llama-index-cli" },
-    { name = "llama-index-core" },
-    { name = "llama-index-embeddings-openai" },
-    { name = "llama-index-indices-managed-llama-cloud" },
-    { name = "llama-index-llms-openai" },
-    { name = "llama-index-multi-modal-llms-openai" },
-    { name = "llama-index-program-openai" },
-    { name = "llama-index-question-gen-openai" },
-    { name = "llama-index-readers-file" },
-    { name = "llama-index-readers-llama-parse" },
-    { name = "nltk" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/43/34/7eb11a6b6fa603fa0a072c1ffaa08d337d805d09feca5235bd42664d9ec4/llama_index-0.12.11.tar.gz", hash = "sha256:b1116946a2414aec104a6c417b847da5b4f077a0966c50ebd2fc445cd713adce", size = 7781 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d5/72/ab8bae2072c0e7786cbe7348d5b45bfb12972dd3a1fdb5cb96c615b779f6/llama_index-0.12.11-py3-none-any.whl", hash = "sha256:007361c35e1981a1656cef287b7bcdf22aa88e7d41b8e3a8ee261bb5a10519a9", size = 6876 },
-]
-
-[[package]]
-name = "llama-index-agent-openai"
-version = "0.4.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "llama-index-llms-openai" },
-    { name = "openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/0b/09/bb3c4d5496f2d79499ca6d323f379e2051473b56a917ed46cf4d0d2aeb05/llama_index_agent_openai-0.4.2.tar.gz", hash = "sha256:0f8aeb091fc834b2667a46ad2417fc8601bf1c08ccfd1a3d15ede90a30eb1a29", size = 10612 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/4d/37/21bdd9adce0e358203a81f245521e829d72547e14ecd6c298ec0327218a1/llama_index_agent_openai-0.4.2-py3-none-any.whl", hash = "sha256:e100b8a743b11fef373b5be31be590b929950a4d7fd9d158b5f014dd8fd7976e", size = 13205 },
-]
-
-[[package]]
-name = "llama-index-cli"
-version = "0.4.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "llama-index-embeddings-openai" },
-    { name = "llama-index-llms-openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/0a/52/81e1448d4dcff5beb1453f397f34f9ac769b7fcdb6b7c8fbd4c20b73e836/llama_index_cli-0.4.0.tar.gz", hash = "sha256:d6ab201359962a8a34368aeda3a49bbbe67e9e009c59bd925c4fb2be4ace3906", size = 24710 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/70/29/2b659e5930ea44253bf99e2afc395daaa2a3edaa579d99e63ea53df03313/llama_index_cli-0.4.0-py3-none-any.whl", hash = "sha256:60d12f89e6b85e80a0cc3a8b531f05a911b5eebaebc37314411476d1ba685904", size = 27785 },
-]
-
-[[package]]
-name = "llama-index-core"
-version = "0.12.11"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "dataclasses-json" },
-    { name = "deprecated" },
-    { name = "dirtyjson" },
-    { name = "filetype" },
-    { name = "fsspec" },
-    { name = "httpx" },
-    { name = "nest-asyncio" },
-    { name = "networkx" },
-    { name = "nltk" },
-    { name = "numpy" },
-    { name = "pillow" },
-    { name = "pydantic" },
-    { name = "pyyaml" },
-    { name = "requests" },
-    { name = "sqlalchemy", extra = ["asyncio"] },
-    { name = "tenacity" },
-    { name = "tiktoken" },
-    { name = "tqdm" },
-    { name = "typing-extensions" },
-    { name = "typing-inspect" },
-    { name = "wrapt" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/8d/a7/1ee40a8bcc5e7ff1dc523f2a26e217b3d7a306d4180b0654e9b4ab519c9c/llama_index_core-0.12.11.tar.gz", hash = "sha256:9a41ca91167ea5eec9ebaac7f5e958b7feddbd8af3bfbf7c393a5edfb994d566", size = 1332167 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d4/fb/3aadbfb0a43a734857802d6c372e70470921aaef3023b5e8f39dbdc6fd94/llama_index_core-0.12.11-py3-none-any.whl", hash = "sha256:3b1e019c899e9e011dfa01c96b7e3f666e0c161035fbca6cb787b4c61e0c94db", size = 1584262 },
-]
-
-[[package]]
-name = "llama-index-embeddings-azure-openai"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "llama-index-embeddings-openai" },
-    { name = "llama-index-llms-azure-openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/48/db/a35c34ff7863315ac133b4ff0386913cbe9986988e7f1c076e1745dbe015/llama_index_embeddings_azure_openai-0.3.0.tar.gz", hash = "sha256:80b0cf977d8b967a08536d65b8e2d0c6c966eeaf1b8fff084e97f3081fd70c34", size = 3111 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/b5/78/eb22765325d03008dae55f98c77053231b9344d2bef6304f3d93121f3468/llama_index_embeddings_azure_openai-0.3.0-py3-none-any.whl", hash = "sha256:2ca61d6b75468d1230cfc1151a878d892b237130b8af09b4434f8c0466d44dfe", size = 3425 },
-]
-
-[[package]]
-name = "llama-index-embeddings-openai"
-version = "0.3.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a1/02/a2604ef3a167131fdd701888f45f16c8efa6d523d02efe8c4e640238f4ea/llama_index_embeddings_openai-0.3.1.tar.gz", hash = "sha256:1368aad3ce24cbaed23d5ad251343cef1eb7b4a06d6563d6606d59cb347fef20", size = 5492 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/bb/45/ca55b91c4ac1b6251d4099fa44121a6c012129822906cadcc27b8cfb33a4/llama_index_embeddings_openai-0.3.1-py3-none-any.whl", hash = "sha256:f15a3d13da9b6b21b8bd51d337197879a453d1605e625a1c6d45e741756c0290", size = 6177 },
-]
-
-[[package]]
-name = "llama-index-indices-managed-llama-cloud"
-version = "0.6.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-cloud" },
-    { name = "llama-index-core" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/58/29afa6086e2080ae27da79949e319f77f08cb7d1b2bd26e56a676dab1338/llama_index_indices_managed_llama_cloud-0.6.3.tar.gz", hash = "sha256:f09e4182cbc2a2bd75ae85cebb1681075247f0d91b931b094cac4315386ce87a", size = 10483 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/43/c6/ebb53a15e63c8da3633a595f53fc965509e8c6707da6a8b1bfa9b7923236/llama_index_indices_managed_llama_cloud-0.6.3-py3-none-any.whl", hash = "sha256:7f125602f624a2d321b6a4130cd98df35eb8c15818a159390755b2c13068f4ce", size = 11077 },
-]
-
-[[package]]
-name = "llama-index-llms-azure-openai"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "azure-identity" },
-    { name = "httpx" },
-    { name = "llama-index-core" },
-    { name = "llama-index-llms-openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/81/d7/21264774d0e0819d869ac2f6527fd6b405340647feb4fef7b6b59c520858/llama_index_llms_azure_openai-0.3.0.tar.gz", hash = "sha256:0feea9319d832c8b5e8e0f397c905e45df54c529b6a778825adcd0d254bd7d63", size = 5557 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/90/49/a90c17bddddb411e0bc2d05bcf393fb03474279fb6fbe20c98db68473d98/llama_index_llms_azure_openai-0.3.0-py3-none-any.whl", hash = "sha256:24091aedf7ba24a7b217d17c4358e62b5d6b43a4d3ca44750d442b02a440d26e", size = 6306 },
-]
-
-[[package]]
-name = "llama-index-llms-openai"
-version = "0.3.13"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/12/0d/bc11eb89f8c912747d3a41186b8b9a2fc2c15cc52af7866689621e22ab4d/llama_index_llms_openai-0.3.13.tar.gz", hash = "sha256:51dda240dae7671c37e84bb50fe77fe6bb58a9b2a7e33dccd84473c9998afcea", size = 14302 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/0a/22/b0dad3dd2b9054d020208cbc86e9fd730c04fe3551a9af2e640593eff6ef/llama_index_llms_openai-0.3.13-py3-none-any.whl", hash = "sha256:caea1d6cb5bdd34518fcefe28b784698c92120ed133e6cd4591f777cd15180b0", size = 14542 },
-]
-
-[[package]]
-name = "llama-index-multi-modal-llms-openai"
-version = "0.4.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "llama-index-llms-openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/eb/32/6f13d3cb79d71504072041d2e83fa67804c7945d2249f7ccadbcbbe15fdc/llama_index_multi_modal_llms_openai-0.4.2.tar.gz", hash = "sha256:3437a08cec85cebbc212aa73da5c9b8b054b4dc628338568435a7df88489476f", size = 5078 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/05/18/14772cebd9674772bc605632c92d4675e86d87a3263c35a90865d6c4918b/llama_index_multi_modal_llms_openai-0.4.2-py3-none-any.whl", hash = "sha256:093f60f59fc423abab110810f8f129b96b0212b9737d74480f0e3e1b715e975b", size = 5855 },
-]
-
-[[package]]
-name = "llama-index-program-openai"
-version = "0.3.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-agent-openai" },
-    { name = "llama-index-core" },
-    { name = "llama-index-llms-openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/7a/b8/24f1103106bfeed04f0e33b587863345c2d7fad001828bb02844a5427fbc/llama_index_program_openai-0.3.1.tar.gz", hash = "sha256:6039a6cdbff62c6388c07e82a157fe2edd3bbef0c5adf292ad8546bf4ec75b82", size = 4818 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/00/59/3f31171c30a08c8ba21155d5241ba174630e57cf43b03d97fd77bf565b51/llama_index_program_openai-0.3.1-py3-none-any.whl", hash = "sha256:93646937395dc5318fd095153d2f91bd632b25215d013d14a87c088887d205f9", size = 5318 },
-]
-
-[[package]]
-name = "llama-index-question-gen-openai"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "llama-index-llms-openai" },
-    { name = "llama-index-program-openai" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/4e/47/c57392e2fb00c0f596f912e7977e3c639ac3314f2aed5d4ac733baa367f1/llama_index_question_gen_openai-0.3.0.tar.gz", hash = "sha256:efd3b468232808e9d3474670aaeab00e41b90f75f52d0c9bfbf11207e0963d62", size = 2608 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7c/2c/765b0dfc2c988bbea267e236c836d7a96c60a20df76d842e43e17401f800/llama_index_question_gen_openai-0.3.0-py3-none-any.whl", hash = "sha256:9b60ec114273a63b50349948666e5744a8f58acb645824e07c979041e8fec598", size = 2899 },
-]
-
-[[package]]
-name = "llama-index-readers-file"
-version = "0.4.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "beautifulsoup4" },
-    { name = "llama-index-core" },
-    { name = "pandas" },
-    { name = "pypdf" },
-    { name = "striprtf" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/bc/35/62edc3eed9d69d9b5b5faae4c0c82ff05e608b07b0c547a988c23f19a79c/llama_index_readers_file-0.4.3.tar.gz", hash = "sha256:07514bebed7ce431c1b3ef9279d09aa3d1bba8e342d661860a033355b98fb33a", size = 22046 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a5/06/f41f795000c623d4cdaf95729a045a2be819c31f39951d5e88f4bccf37db/llama_index_readers_file-0.4.3-py3-none-any.whl", hash = "sha256:c669da967ea534e3af3660f9fd730c71c725288f5c57906bcce338414ebeee5c", size = 38914 },
-]
-
-[[package]]
-name = "llama-index-readers-llama-parse"
-version = "0.4.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "llama-parse" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/35/30/4611821286f82ba7b5842295607baa876262db86f88b87d83595eed172bf/llama_index_readers_llama_parse-0.4.0.tar.gz", hash = "sha256:e99ec56f4f8546d7fda1a7c1ae26162fb9acb7ebcac343b5abdb4234b4644e0f", size = 2472 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/68/4f/e30d4257fe9e4224f5612b77fe99aaceddae411b2e74ca30534491de3e6f/llama_index_readers_llama_parse-0.4.0-py3-none-any.whl", hash = "sha256:574e48386f28d2c86c3f961ca4a4906910312f3400dd0c53014465bfbc6b32bf", size = 2472 },
-]
-
-[[package]]
-name = "llama-index-readers-web"
-version = "0.3.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "beautifulsoup4" },
-    { name = "chromedriver-autoinstaller" },
-    { name = "html2text" },
-    { name = "llama-index-core" },
-    { name = "newspaper3k" },
-    { name = "playwright" },
-    { name = "requests" },
-    { name = "selenium" },
-    { name = "spider-client" },
-    { name = "urllib3" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/89/a5/14e4277c871194092e014fd893f8f17a7c84f447a254696d7985ab9e603c/llama_index_readers_web-0.3.3.tar.gz", hash = "sha256:740373b17456cc46a9b39810253a3c1adfc8814d40f88798bea42115a10626ce", size = 53969 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/98/40/6e290cac34ac217b47347c7b0268114aef1f0c836998647d0c9f0fabc8f0/llama_index_readers_web-0.3.3-py3-none-any.whl", hash = "sha256:ab166bb14a56f5b10b637d6633c861d86bcaa72e7e123c4e31d304e6b1d88efe", size = 76616 },
-]
-
-[[package]]
-name = "llama-index-readers-wikipedia"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ae/f1/1bd33ebbd003f1e19e9a77a85d0e77c0dd0c904de50cc9212cc718648813/llama_index_readers_wikipedia-0.3.0.tar.gz", hash = "sha256:77972387cd5410c981bd427699613de63e76889f99816512fc3fce3b2eca440a", size = 2445 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7b/8a/c85a69d9899fd6b7176bcbf6d19579feb1110e340a48b486f3682bc1bf60/llama_index_readers_wikipedia-0.3.0-py3-none-any.whl", hash = "sha256:1723441901a3a19f323872e3c5a968bbfc98cdc5f35e901c99e79f0e8cb7fa57", size = 2702 },
-]
-
-[[package]]
-name = "llama-index-tools-wikipedia"
-version = "0.3.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "llama-index-core" },
-    { name = "wikipedia" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/86/fc/0ebe0913694a3582c0ae2c96cafb48689a9d012766e5b8a32d59932009de/llama_index_tools_wikipedia-0.3.0.tar.gz", hash = "sha256:8e3fc5ae8a479aacc6640c6c30a66f9848762bf8ebbbc4ceab41e8a4762a664c", size = 2487 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/60/89/0d7aa9a41ed0a0768790da770ef057416b81a92ecc35dc9f9d70a86abbb1/llama_index_tools_wikipedia-0.3.0-py3-none-any.whl", hash = "sha256:aa76c39237056b3ed727a23aadc65f34c5b500449ee9ec2efaced055f3ff9938", size = 2712 },
-]
-
-[[package]]
-name = "llama-parse"
-version = "0.5.19"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "click" },
-    { name = "llama-index-core" },
-    { name = "pydantic" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/3b/02/63839a55f6f207110400c4f394152fd0290e9f8e450226b02a87cfdbd835/llama_parse-0.5.19.tar.gz", hash = "sha256:db69da70e199a2664705eb983a70fa92b7cee19dd6cff175af7692a0b8a4dd53", size = 16100 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/38/b7/3ff106e8199992bb62e72f195c8f6f2f2fe4a185f5f92746f0ed9db5c5d2/llama_parse-0.5.19-py3-none-any.whl", hash = "sha256:715cc895d183531b4299359d4f4004089b2e522f5f137f316084e7aa04035b62", size = 15421 },
-]
-
 [[package]]
 name = "llvmlite"
 version = "0.43.0"
@@ -3579,9 +2551,6 @@ requires-dist = [
     { name = "autogen-ext", extras = ["openai", "magentic-one"], editable = "packages/autogen-ext" },
 ]
 
-[package.metadata.requires-dev]
-dev = []
-
 [[package]]
 name = "mako"
 version = "1.3.8"
@@ -3618,14 +2587,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
 ]
 
-[package.optional-dependencies]
-linkify = [
-    { name = "linkify-it-py" },
-]
-plugins = [
-    { name = "mdit-py-plugins" },
-]
-
 [[package]]
 name = "markdownify"
 version = "0.14.1"
@@ -3768,18 +2729,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 },
 ]
 
-[[package]]
-name = "mdit-py-plugins"
-version = "0.4.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "markdown-it-py" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 },
-]
-
 [[package]]
 name = "mdurl"
 version = "0.1.2"
@@ -3851,47 +2800,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 },
 ]
 
-[[package]]
-name = "msgpack"
-version = "1.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/cb/d0/7555686ae7ff5731205df1012ede15dd9d927f6227ea151e901c7406af4f/msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e", size = 167260 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/4b/f9/a892a6038c861fa849b11a2bb0502c07bc698ab6ea53359e5771397d883b/msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd", size = 150428 },
-    { url = "https://files.pythonhosted.org/packages/df/7a/d174cc6a3b6bb85556e6a046d3193294a92f9a8e583cdbd46dc8a1d7e7f4/msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d", size = 84131 },
-    { url = "https://files.pythonhosted.org/packages/08/52/bf4fbf72f897a23a56b822997a72c16de07d8d56d7bf273242f884055682/msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5", size = 81215 },
-    { url = "https://files.pythonhosted.org/packages/02/95/dc0044b439b518236aaf012da4677c1b8183ce388411ad1b1e63c32d8979/msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5", size = 371229 },
-    { url = "https://files.pythonhosted.org/packages/ff/75/09081792db60470bef19d9c2be89f024d366b1e1973c197bb59e6aabc647/msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e", size = 378034 },
-    { url = "https://files.pythonhosted.org/packages/32/d3/c152e0c55fead87dd948d4b29879b0f14feeeec92ef1fd2ec21b107c3f49/msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b", size = 363070 },
-    { url = "https://files.pythonhosted.org/packages/d9/2c/82e73506dd55f9e43ac8aa007c9dd088c6f0de2aa19e8f7330e6a65879fc/msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f", size = 359863 },
-    { url = "https://files.pythonhosted.org/packages/cb/a0/3d093b248837094220e1edc9ec4337de3443b1cfeeb6e0896af8ccc4cc7a/msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68", size = 368166 },
-    { url = "https://files.pythonhosted.org/packages/e4/13/7646f14f06838b406cf5a6ddbb7e8dc78b4996d891ab3b93c33d1ccc8678/msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b", size = 370105 },
-    { url = "https://files.pythonhosted.org/packages/67/fa/dbbd2443e4578e165192dabbc6a22c0812cda2649261b1264ff515f19f15/msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044", size = 68513 },
-    { url = "https://files.pythonhosted.org/packages/24/ce/c2c8fbf0ded750cb63cbcbb61bc1f2dfd69e16dca30a8af8ba80ec182dcd/msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f", size = 74687 },
-    { url = "https://files.pythonhosted.org/packages/b7/5e/a4c7154ba65d93be91f2f1e55f90e76c5f91ccadc7efc4341e6f04c8647f/msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7", size = 150803 },
-    { url = "https://files.pythonhosted.org/packages/60/c2/687684164698f1d51c41778c838d854965dd284a4b9d3a44beba9265c931/msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa", size = 84343 },
-    { url = "https://files.pythonhosted.org/packages/42/ae/d3adea9bb4a1342763556078b5765e666f8fdf242e00f3f6657380920972/msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701", size = 81408 },
-    { url = "https://files.pythonhosted.org/packages/dc/17/6313325a6ff40ce9c3207293aee3ba50104aed6c2c1559d20d09e5c1ff54/msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6", size = 396096 },
-    { url = "https://files.pythonhosted.org/packages/a8/a1/ad7b84b91ab5a324e707f4c9761633e357820b011a01e34ce658c1dda7cc/msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59", size = 403671 },
-    { url = "https://files.pythonhosted.org/packages/bb/0b/fd5b7c0b308bbf1831df0ca04ec76fe2f5bf6319833646b0a4bd5e9dc76d/msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0", size = 387414 },
-    { url = "https://files.pythonhosted.org/packages/f0/03/ff8233b7c6e9929a1f5da3c7860eccd847e2523ca2de0d8ef4878d354cfa/msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e", size = 383759 },
-    { url = "https://files.pythonhosted.org/packages/1f/1b/eb82e1fed5a16dddd9bc75f0854b6e2fe86c0259c4353666d7fab37d39f4/msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6", size = 394405 },
-    { url = "https://files.pythonhosted.org/packages/90/2e/962c6004e373d54ecf33d695fb1402f99b51832631e37c49273cc564ffc5/msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5", size = 396041 },
-    { url = "https://files.pythonhosted.org/packages/f8/20/6e03342f629474414860c48aeffcc2f7f50ddaf351d95f20c3f1c67399a8/msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88", size = 68538 },
-    { url = "https://files.pythonhosted.org/packages/aa/c4/5a582fc9a87991a3e6f6800e9bb2f3c82972912235eb9539954f3e9997c7/msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788", size = 74871 },
-    { url = "https://files.pythonhosted.org/packages/e1/d6/716b7ca1dbde63290d2973d22bbef1b5032ca634c3ff4384a958ec3f093a/msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d", size = 152421 },
-    { url = "https://files.pythonhosted.org/packages/70/da/5312b067f6773429cec2f8f08b021c06af416bba340c912c2ec778539ed6/msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2", size = 85277 },
-    { url = "https://files.pythonhosted.org/packages/28/51/da7f3ae4462e8bb98af0d5bdf2707f1b8c65a0d4f496e46b6afb06cbc286/msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420", size = 82222 },
-    { url = "https://files.pythonhosted.org/packages/33/af/dc95c4b2a49cff17ce47611ca9ba218198806cad7796c0b01d1e332c86bb/msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2", size = 392971 },
-    { url = "https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39", size = 401403 },
-    { url = "https://files.pythonhosted.org/packages/97/8c/e333690777bd33919ab7024269dc3c41c76ef5137b211d776fbb404bfead/msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f", size = 385356 },
-    { url = "https://files.pythonhosted.org/packages/57/52/406795ba478dc1c890559dd4e89280fa86506608a28ccf3a72fbf45df9f5/msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247", size = 383028 },
-    { url = "https://files.pythonhosted.org/packages/e7/69/053b6549bf90a3acadcd8232eae03e2fefc87f066a5b9fbb37e2e608859f/msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c", size = 391100 },
-    { url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254 },
-    { url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085 },
-    { url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347 },
-]
-
 [[package]]
 name = "multidict"
 version = "6.1.0"
@@ -3949,35 +2857,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 },
 ]
 
-[[package]]
-name = "mypy"
-version = "1.13.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "mypy-extensions" },
-    { name = "tomli", marker = "python_full_version < '3.11'" },
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/5e/8c/206de95a27722b5b5a8c85ba3100467bd86299d92a4f71c6b9aa448bfa2f/mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", size = 11020731 },
-    { url = "https://files.pythonhosted.org/packages/ab/bb/b31695a29eea76b1569fd28b4ab141a1adc9842edde080d1e8e1776862c7/mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", size = 10184276 },
-    { url = "https://files.pythonhosted.org/packages/a5/2d/4a23849729bb27934a0e079c9c1aad912167d875c7b070382a408d459651/mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", size = 12587706 },
-    { url = "https://files.pythonhosted.org/packages/5c/c3/d318e38ada50255e22e23353a469c791379825240e71b0ad03e76ca07ae6/mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", size = 13105586 },
-    { url = "https://files.pythonhosted.org/packages/4a/25/3918bc64952370c3dbdbd8c82c363804678127815febd2925b7273d9482c/mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", size = 9632318 },
-    { url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 },
-    { url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 },
-    { url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 },
-    { url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 },
-    { url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 },
-    { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 },
-    { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 },
-    { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 },
-    { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 },
-    { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 },
-    { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 },
-]
-
 [[package]]
 name = "mypy-extensions"
 version = "1.0.0"
@@ -3987,57 +2866,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
 ]
 
-[[package]]
-name = "mypy-protobuf"
-version = "3.6.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "protobuf" },
-    { name = "types-protobuf" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/4d/6f/282d64d66bf48ce60e38a6560753f784e0f88ab245ac2fb5e93f701a36cd/mypy-protobuf-3.6.0.tar.gz", hash = "sha256:02f242eb3409f66889f2b1a3aa58356ec4d909cdd0f93115622e9e70366eca3c", size = 24445 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/e8/73/d6b999782ae22f16971cc05378b3b33f6a89ede3b9619e8366aa23484bca/mypy_protobuf-3.6.0-py3-none-any.whl", hash = "sha256:56176e4d569070e7350ea620262478b49b7efceba4103d468448f1d21492fd6c", size = 16434 },
-]
-
-[[package]]
-name = "myst-nb"
-version = "1.1.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "importlib-metadata" },
-    { name = "ipykernel" },
-    { name = "ipython" },
-    { name = "jupyter-cache" },
-    { name = "myst-parser" },
-    { name = "nbclient" },
-    { name = "nbformat" },
-    { name = "pyyaml" },
-    { name = "sphinx" },
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/04/e3/01c093f6a46be2edc0fd370cbf6d227495ea19452939b2810b36657c63d4/myst_nb-1.1.2.tar.gz", hash = "sha256:961b4005657029ca89892a4c75edbf0856c54ceaf6172368b46bf7676c1f7700", size = 78036 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/04/45/cf78b2f09c46b36f486b75c34a8b48580e53b543bd9a467b3c7eb9054b70/myst_nb-1.1.2-py3-none-any.whl", hash = "sha256:9b7034e5d62640cb6daf03f9ca16ef45d0462fced27944c77aa3f98c7cdcd566", size = 80281 },
-]
-
-[[package]]
-name = "myst-parser"
-version = "4.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "docutils" },
-    { name = "jinja2" },
-    { name = "markdown-it-py" },
-    { name = "mdit-py-plugins" },
-    { name = "pyyaml" },
-    { name = "sphinx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/85/55/6d1741a1780e5e65038b74bce6689da15f620261c490c3511eb4c12bac4b/myst_parser-4.0.0.tar.gz", hash = "sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531", size = 93858 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl", hash = "sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d", size = 84563 },
-]
-
 [[package]]
 name = "nbclient"
 version = "0.10.2"
@@ -4068,21 +2896,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 },
 ]
 
-[[package]]
-name = "nbqa"
-version = "1.9.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "autopep8" },
-    { name = "ipython" },
-    { name = "tokenize-rt" },
-    { name = "tomli" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/aa/76/62d2609924cf34445148cd6b5de694cf64c179cc416cac93182579620e57/nbqa-1.9.1.tar.gz", hash = "sha256:a1f4bcf587c597302fed295951001fc4e1be4ce0e77e1ab1b25ac2fbe3db0cdd", size = 38348 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/28/88/4789719fbbe166d12d345b3ac66b96105f10001b16e00a9765ba29261a21/nbqa-1.9.1-py3-none-any.whl", hash = "sha256:95552d2f6c2c038136252a805aa78d85018aef922586270c3a074332737282e5", size = 35259 },
-]
-
 [[package]]
 name = "nest-asyncio"
 version = "1.6.0"
@@ -4101,30 +2914,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 },
 ]
 
-[[package]]
-name = "newspaper3k"
-version = "0.2.8"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "beautifulsoup4" },
-    { name = "cssselect" },
-    { name = "feedfinder2" },
-    { name = "feedparser" },
-    { name = "jieba3k" },
-    { name = "lxml" },
-    { name = "nltk" },
-    { name = "pillow" },
-    { name = "python-dateutil" },
-    { name = "pyyaml" },
-    { name = "requests" },
-    { name = "tinysegmenter" },
-    { name = "tldextract" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/fb/8f8525be0cafa48926e85b0c06a7cb3e2a892d340b8036f8c8b1b572df1c/newspaper3k-0.2.8.tar.gz", hash = "sha256:9f1bd3e1fb48f400c715abf875cc7b0a67b7ddcd87f50c9aeeb8fcbbbd9004fb", size = 205685 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d7/b9/51afecb35bb61b188a4b44868001de348a0e8134b4dfa00ffc191567c4b9/newspaper3k-0.2.8-py3-none-any.whl", hash = "sha256:44a864222633d3081113d1030615991c3dbba87239f6bbf59d91240f71a22e3e", size = 211132 },
-]
-
 [[package]]
 name = "nltk"
 version = "3.9.1"
@@ -4140,15 +2929,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/4d/66/7d9e26593edda06e8cb531874633f7c2372279c3b0f46235539fe546df8b/nltk-3.9.1-py3-none-any.whl", hash = "sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1", size = 1505442 },
 ]
 
-[[package]]
-name = "nodeenv"
-version = "1.9.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 },
-]
-
 [[package]]
 name = "numba"
 version = "0.60.0"
@@ -4249,7 +3029,7 @@ name = "nvidia-cudnn-cu12"
 version = "9.1.0.70"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "nvidia-cublas-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 },
@@ -4260,7 +3040,7 @@ name = "nvidia-cufft-cu12"
 version = "11.2.1.3"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/7a/8a/0e728f749baca3fbeffad762738276e5df60851958be7783af121a7221e7/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399", size = 211422548 },
@@ -4281,9 +3061,9 @@ name = "nvidia-cusolver-cu12"
 version = "11.6.1.9"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
-    { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
-    { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "nvidia-cublas-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "nvidia-cusparse-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/46/6b/a5c33cf16af09166845345275c34ad2190944bcc6026797a39f8e0a282e0/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e", size = 127634111 },
@@ -4295,7 +3075,7 @@ name = "nvidia-cusparse-cu12"
 version = "12.3.1.170"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/96/a9/c0d2f83a53d40a4a41be14cea6a0bf9e668ffcf8b004bd65633f433050c0/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3", size = 207381987 },
@@ -4520,93 +3300,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/fb/1f/737dcdbc9fea2fa96c1b392ae47275165a7c641663fbb08a8d252968eed2/opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7", size = 63970 },
 ]
 
-[[package]]
-name = "opentelemetry-exporter-otlp"
-version = "1.27.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "opentelemetry-exporter-otlp-proto-grpc" },
-    { name = "opentelemetry-exporter-otlp-proto-http" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/fc/d3/8156cc14e8f4573a3572ee7f30badc7aabd02961a09acc72ab5f2c789ef1/opentelemetry_exporter_otlp-1.27.0.tar.gz", hash = "sha256:4a599459e623868cc95d933c301199c2367e530f089750e115599fccd67cb2a1", size = 6166 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/59/6d/95e1fc2c8d945a734db32e87a5aa7a804f847c1657a21351df9338bd1c9c/opentelemetry_exporter_otlp-1.27.0-py3-none-any.whl", hash = "sha256:7688791cbdd951d71eb6445951d1cfbb7b6b2d7ee5948fac805d404802931145", size = 7001 },
-]
-
-[[package]]
-name = "opentelemetry-exporter-otlp-proto-common"
-version = "1.27.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "opentelemetry-proto" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/cd/2e/7eaf4ba595fb5213cf639c9158dfb64aacb2e4c7d74bfa664af89fa111f4/opentelemetry_exporter_otlp_proto_common-1.27.0.tar.gz", hash = "sha256:159d27cf49f359e3798c4c3eb8da6ef4020e292571bd8c5604a2a573231dd5c8", size = 17860 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/41/27/4610ab3d9bb3cde4309b6505f98b3aabca04a26aa480aa18cede23149837/opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl", hash = "sha256:675db7fffcb60946f3a5c43e17d1168a3307a94a930ecf8d2ea1f286f3d4f79a", size = 17848 },
-]
-
-[[package]]
-name = "opentelemetry-exporter-otlp-proto-grpc"
-version = "1.27.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "deprecated" },
-    { name = "googleapis-common-protos" },
-    { name = "grpcio" },
-    { name = "opentelemetry-api" },
-    { name = "opentelemetry-exporter-otlp-proto-common" },
-    { name = "opentelemetry-proto" },
-    { name = "opentelemetry-sdk" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a1/d0/c1e375b292df26e0ffebf194e82cd197e4c26cc298582bda626ce3ce74c5/opentelemetry_exporter_otlp_proto_grpc-1.27.0.tar.gz", hash = "sha256:af6f72f76bcf425dfb5ad11c1a6d6eca2863b91e63575f89bb7b4b55099d968f", size = 26244 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/8d/80/32217460c2c64c0568cea38410124ff680a9b65f6732867bbf857c4d8626/opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl", hash = "sha256:56b5bbd5d61aab05e300d9d62a6b3c134827bbd28d0b12f2649c2da368006c9e", size = 18541 },
-]
-
-[[package]]
-name = "opentelemetry-exporter-otlp-proto-http"
-version = "1.27.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "deprecated" },
-    { name = "googleapis-common-protos" },
-    { name = "opentelemetry-api" },
-    { name = "opentelemetry-exporter-otlp-proto-common" },
-    { name = "opentelemetry-proto" },
-    { name = "opentelemetry-sdk" },
-    { name = "requests" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/31/0a/f05c55e8913bf58a033583f2580a0ec31a5f4cf2beacc9e286dcb74d6979/opentelemetry_exporter_otlp_proto_http-1.27.0.tar.gz", hash = "sha256:2103479092d8eb18f61f3fbff084f67cc7f2d4a7d37e75304b8b56c1d09ebef5", size = 15059 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/2d/8d/4755884afc0b1db6000527cac0ca17273063b6142c773ce4ecd307a82e72/opentelemetry_exporter_otlp_proto_http-1.27.0-py3-none-any.whl", hash = "sha256:688027575c9da42e179a69fe17e2d1eba9b14d81de8d13553a21d3114f3b4d75", size = 17203 },
-]
-
-[[package]]
-name = "opentelemetry-instrumentation"
-version = "0.48b0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "opentelemetry-api" },
-    { name = "setuptools" },
-    { name = "wrapt" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/04/0e/d9394839af5d55c8feb3b22cd11138b953b49739b20678ca96289e30f904/opentelemetry_instrumentation-0.48b0.tar.gz", hash = "sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35", size = 24724 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/0a/7f/405c41d4f359121376c9d5117dcf68149b8122d3f6c718996d037bd4d800/opentelemetry_instrumentation-0.48b0-py3-none-any.whl", hash = "sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44", size = 29449 },
-]
-
-[[package]]
-name = "opentelemetry-proto"
-version = "1.27.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "protobuf" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/9a/59/959f0beea798ae0ee9c979b90f220736fbec924eedbefc60ca581232e659/opentelemetry_proto-1.27.0.tar.gz", hash = "sha256:33c9345d91dafd8a74fc3d7576c5a38f18b7fdf8d02983ac67485386132aedd6", size = 34749 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/94/56/3d2d826834209b19a5141eed717f7922150224d1a982385d19a9444cbf8d/opentelemetry_proto-1.27.0-py3-none-any.whl", hash = "sha256:b133873de5581a50063e1e4b29cdcf0c5e253a8c2d8dc1229add20a4c3830ace", size = 52464 },
-]
-
 [[package]]
 name = "opentelemetry-sdk"
 version = "1.27.0"
@@ -4681,18 +3374,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/70/7f/f2d346819a273653825e7c92dc26418c8da506003c9fc1dfe8157e733b2e/orjson-3.10.14-cp312-cp312-win_amd64.whl", hash = "sha256:175cafd322e458603e8ce73510a068d16b6e6f389c13f69bf16de0e843d7d406", size = 133663 },
 ]
 
-[[package]]
-name = "outcome"
-version = "1.3.0.post0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "attrs" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692 },
-]
-
 [[package]]
 name = "overrides"
 version = "7.7.0"
@@ -4746,19 +3427,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 },
 ]
 
-[[package]]
-name = "pandas-stubs"
-version = "2.2.3.241126"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "numpy" },
-    { name = "types-pytz" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/90/86/93c545d149c3e1fe1c4c55478cc3a69859d0ea3467e1d9892e9eb28cb1e7/pandas_stubs-2.2.3.241126.tar.gz", hash = "sha256:cf819383c6d9ae7d4dabf34cd47e1e45525bb2f312e6ad2939c2c204cb708acd", size = 104204 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/6f/ab/ed42acf15bab2e86e5c49fad4aa038315233c4c2d22f41b49faa4d837516/pandas_stubs-2.2.3.241126-py3-none-any.whl", hash = "sha256:74aa79c167af374fe97068acc90776c0ebec5266a6e5c69fe11e9c2cf51f2267", size = 158280 },
-]
-
 [[package]]
 name = "parse"
 version = "1.20.2"
@@ -4777,15 +3445,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 },
 ]
 
-[[package]]
-name = "pastel"
-version = "0.2.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955 },
-]
-
 [[package]]
 name = "pathable"
 version = "0.4.4"
@@ -4816,15 +3475,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/87/2b/b50d3d08ea0fc419c183a84210571eba005328efa62b6b98bc28e9ead32a/patsy-1.0.1-py2.py3-none-any.whl", hash = "sha256:751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c", size = 232923 },
 ]
 
-[[package]]
-name = "pbr"
-version = "6.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b2/35/80cf8f6a4f34017a7fe28242dc45161a1baa55c41563c354d8147e8358b2/pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", size = 124032 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/1d/44/6a65ecd630393d47ad3e7d5354768cb7f9a10b3a0eb2cd8c6f52b28211ee/pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a", size = 108529 },
-]
-
 [[package]]
 name = "pdfminer-six"
 version = "20240706"
@@ -4898,15 +3548,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/41/67/936f9814bdd74b2dfd4822f1f7725ab5d8ff4103919a1664eb4874c58b2f/pillow-11.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0", size = 2626353 },
 ]
 
-[[package]]
-name = "pip"
-version = "24.3.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 },
-]
-
 [[package]]
 name = "platformdirs"
 version = "4.3.6"
@@ -4943,40 +3584,12 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
 ]
 
-[[package]]
-name = "poethepoet"
-version = "0.32.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pastel" },
-    { name = "pyyaml" },
-    { name = "tomli", marker = "python_full_version < '3.11'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/d1/10/11f929bad564b2dbc5c119ecf0f37456ac24538bb4a70c76f140a2aa695a/poethepoet-0.32.1.tar.gz", hash = "sha256:471e1a025812dcd3d2997e30989681be5ab0a49232ee5fba94859629671c9584", size = 61391 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/85/a5/fc26dd508f33809bdd3823a0170e492fe44ad7e097c32c4a52e16cf3ecb0/poethepoet-0.32.1-py3-none-any.whl", hash = "sha256:d1e0a52a2f677870fac17dfb26bfe4910242756ac821443ef31f90ad26227c2d", size = 81729 },
-]
-
-[[package]]
-name = "polars"
-version = "1.19.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/26/d9/66ada2204483c4c4d83898ade77eacd5fbef26ae4975a0d7d5de134ca46a/polars-1.19.0.tar.gz", hash = "sha256:b52ada5c43fcdadf64f282522198c5549ee4e46ea57d236a4d7e572643070d9d", size = 4267947 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/c0/7d/e8645281281d44d96752443366ceef2df76c9c1e17dce040111abb6a4a12/polars-1.19.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:51c01837268a1aa41785e60ed7d3363d4b52f652ab0eef4981f887bdfa2e9ca7", size = 29472039 },
-    { url = "https://files.pythonhosted.org/packages/d7/fb/7e5054598d6bb7a47e4ca086797bae61270f7d570350cf779dd97384d913/polars-1.19.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:20f8235e810f6ee795d7a215a3560945e6a1b57d017f87ba0c8542dced1fc665", size = 26150541 },
-    { url = "https://files.pythonhosted.org/packages/ba/ba/6d715730c28b035abd308fc2cf0fcbae0cedea6216797e83ce4a9a96c6d4/polars-1.19.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0ea51f7b3553652bf0d53f3b925e969a898d4feb9980acecf8e3037d696903", size = 32751173 },
-    { url = "https://files.pythonhosted.org/packages/ea/9a/bee8ab37ab82b8eea75170afa3b37ea7e1df74e4c4da8f6c93b3009977fd/polars-1.19.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:30305ef4e1b634c67a5d985832296fade9908482c5b1abb0100800808b2d090e", size = 29704437 },
-    { url = "https://files.pythonhosted.org/packages/57/ec/74afa5699e37e03e3acc7f241f4e2c3e8c91847524005424d9cf038b3034/polars-1.19.0-cp39-abi3-win_amd64.whl", hash = "sha256:de4aa45e24f8f94a1da9cc6031a7db6fa65ac7de8246fac0bc581ebb427d0643", size = 32846039 },
-    { url = "https://files.pythonhosted.org/packages/cf/5b/c6f6c70ddc9d3070dee65f4640437cb84ccb4cca04f7a81b01db15329ae3/polars-1.19.0-cp39-abi3-win_arm64.whl", hash = "sha256:d7ca7aeb63fa22c0a00f6cfa95dd5252c249e83dd4d1b954583a59f97a8e407b", size = 29029208 },
-]
-
 [[package]]
 name = "portalocker"
 version = "2.10.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "pywin32", marker = "sys_platform == 'win32'" },
+    { name = "pywin32", marker = "platform_system == 'Windows'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 }
 wheels = [
@@ -5244,15 +3857,6 @@ dependencies = [
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/ee/52/9aa428633ef5aba4b096b2b2f8d046ece613cecab28b4ceed54126d25ea5/pybars4-0.9.13.tar.gz", hash = "sha256:425817da20d4ad320bc9b8e77a60cab1bb9d3c677df3dce224925c3310fcd635", size = 29907 }
 
-[[package]]
-name = "pycodestyle"
-version = "2.12.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284 },
-]
-
 [[package]]
 name = "pycparser"
 version = "2.22"
@@ -5350,25 +3954,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718 },
 ]
 
-[[package]]
-name = "pydata-sphinx-theme"
-version = "0.15.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "accessible-pygments" },
-    { name = "babel" },
-    { name = "beautifulsoup4" },
-    { name = "docutils" },
-    { name = "packaging" },
-    { name = "pygments" },
-    { name = "sphinx" },
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/67/ea/3ab478cccacc2e8ef69892c42c44ae547bae089f356c4b47caf61730958d/pydata_sphinx_theme-0.15.4.tar.gz", hash = "sha256:7762ec0ac59df3acecf49fd2f889e1b4565dbce8b88b2e29ee06fdd90645a06d", size = 2400673 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/e7/d3/c622950d87a2ffd1654208733b5bd1c5645930014abed8f4c0d74863988b/pydata_sphinx_theme-0.15.4-py3-none-any.whl", hash = "sha256:2136ad0e9500d0949f96167e63f3e298620040aea8f9c74621959eda5d4cf8e6", size = 4640157 },
-]
-
 [[package]]
 name = "pydub"
 version = "0.25.1"
@@ -5461,18 +4046,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/1c/a7/c8a2d361bf89c0d9577c934ebb7421b25dc84bf3a8e3ac0a40aed9acc547/pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1", size = 107716 },
 ]
 
-[[package]]
-name = "pypdf"
-version = "5.1.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "typing-extensions", marker = "python_full_version < '3.11'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/6b/9a/72d74f05f64895ebf1c7f6646cf7fe6dd124398c5c49240093f92d6f0fdd/pypdf-5.1.0.tar.gz", hash = "sha256:425a129abb1614183fd1aca6982f650b47f8026867c0ce7c4b9f281c443d2740", size = 5011381 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/04/fc/6f52588ac1cb4400a7804ef88d0d4e00cfe57a7ac6793ec3b00de5a8758b/pypdf-5.1.0-py3-none-any.whl", hash = "sha256:3bd4f503f4ebc58bae40d81e81a9176c400cbbac2ba2d877367595fb524dfdfc", size = 297976 },
-]
-
 [[package]]
 name = "pyreadline3"
 version = "3.5.4"
@@ -5482,28 +4055,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178 },
 ]
 
-[[package]]
-name = "pyright"
-version = "1.1.389"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "nodeenv" },
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/72/4e/9a5ab8745e7606b88c2c7ca223449ac9d82a71fd5e31df47b453f2cb39a1/pyright-1.1.389.tar.gz", hash = "sha256:716bf8cc174ab8b4dcf6828c3298cac05c5ed775dda9910106a5dcfe4c7fe220", size = 21940 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl", hash = "sha256:41e9620bba9254406dc1f621a88ceab5a88af4c826feb4f614d95691ed243a60", size = 18581 },
-]
-
-[[package]]
-name = "pysocks"
-version = "1.7.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 },
-]
-
 [[package]]
 name = "pytest"
 version = "8.3.4"
@@ -5521,56 +4072,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 },
 ]
 
-[[package]]
-name = "pytest-asyncio"
-version = "0.25.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pytest" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400 },
-]
-
-[[package]]
-name = "pytest-cov"
-version = "6.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "coverage", extra = ["toml"] },
-    { name = "pytest" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 },
-]
-
-[[package]]
-name = "pytest-mock"
-version = "3.14.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pytest" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 },
-]
-
-[[package]]
-name = "pytest-xdist"
-version = "3.6.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "execnet" },
-    { name = "pytest" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108 },
-]
-
 [[package]]
 name = "python-dateutil"
 version = "2.9.0.post0"
@@ -5592,27 +4093,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
 ]
 
-[[package]]
-name = "python-engineio"
-version = "4.11.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "simple-websocket" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/52/e0/a9e0fe427ce7f1b7dbf9531fa00ffe4b557c4a7bc8e71891c115af123170/python_engineio-4.11.2.tar.gz", hash = "sha256:145bb0daceb904b4bb2d3eb2d93f7dbb7bb87a6a0c4f20a94cc8654dec977129", size = 91381 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/07/8f/978a0b913e3f8ad33a9a2fe204d32efe3d1ee34ecb1f2829c1cfbdd92082/python_engineio-4.11.2-py3-none-any.whl", hash = "sha256:f0971ac4c65accc489154fe12efd88f53ca8caf04754c46a66e85f5102ef22ad", size = 59239 },
-]
-
-[[package]]
-name = "python-multipart"
-version = "0.0.18"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b4/86/b6b38677dec2e2e7898fc5b6f7e42c2d011919a92d25339451892f27b89c/python_multipart-0.0.18.tar.gz", hash = "sha256:7a68db60c8bfb82e460637fa4750727b45af1d5e2ed215593f917f64694d34fe", size = 36622 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/13/6b/b60f47101ba2cac66b4a83246630e68ae9bbe2e614cbae5f4465f46dee13/python_multipart-0.0.18-py3-none-any.whl", hash = "sha256:efe91480f485f6a361427a541db4796f9e1591afc0fb8e7a4ba06bfbc6708996", size = 24389 },
-]
-
 [[package]]
 name = "python-pptx"
 version = "1.0.2"
@@ -5628,31 +4108,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d9/4f/00be2196329ebbff56ce564aa94efb0fbc828d00de250b1980de1a34ab49/python_pptx-1.0.2-py3-none-any.whl", hash = "sha256:160838e0b8565a8b1f67947675886e9fea18aa5e795db7ae531606d68e785cba", size = 472788 },
 ]
 
-[[package]]
-name = "python-slugify"
-version = "8.0.4"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "text-unidecode" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051 },
-]
-
-[[package]]
-name = "python-socketio"
-version = "5.12.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "bidict" },
-    { name = "python-engineio" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/d0/40ed38076e8aee94785d546d3e3a1cae393da5806a8530be877187e2875f/python_socketio-5.12.1.tar.gz", hash = "sha256:0299ff1f470b676c09c1bfab1dead25405077d227b2c13cf217a34dadc68ba9c", size = 119991 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/8a/a3/c69806f30dd81df5a99d592e7db4c930c3a9b098555aa97b0eb866b20b11/python_socketio-5.12.1-py3-none-any.whl", hash = "sha256:24a0ea7cfff0e021eb28c68edbf7914ee4111bdf030b95e4d250c4dc9af7a386", size = 76947 },
-]
-
 [[package]]
 name = "pytz"
 version = "2024.2"
@@ -5770,8 +4225,7 @@ name = "redis"
 version = "5.2.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
-    { name = "async-timeout", version = "5.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.11.3'" },
+    { name = "async-timeout", marker = "python_full_version < '3.11.3'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/47/da/d283a37303a995cd36f8b92db85135153dc4f7a8e4441aa827721b442cfb/redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f", size = 4608355 }
 wheels = [
@@ -5860,18 +4314,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
 ]
 
-[[package]]
-name = "requests-file"
-version = "2.1.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "requests" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/72/97/bf44e6c6bd8ddbb99943baf7ba8b1a8485bcd2fe0e55e5708d7fee4ff1ae/requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658", size = 6891 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d7/25/dd878a121fcfdf38f52850f11c512e13ec87c2ea72385933818e5b6c15ce/requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c", size = 4244 },
-]
-
 [[package]]
 name = "requests-toolbelt"
 version = "1.0.0"
@@ -6028,30 +4470,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d7/8f/c3654f6f1ddb75daf3922c3d8fc6005b1ab56671ad56ffb874d908bfa668/ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", size = 115523 },
 ]
 
-[[package]]
-name = "ruff"
-version = "0.4.8"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/0f/6b/4545638200466af8b9407bd0d5bea1ce426328eaa9714f8d3ef1a43fc0e6/ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268", size = 2559790 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/e6/fd/cbdfeba4f72856853705b4dfc01c232fd6000cdbbde801224783de65c2a6/ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066", size = 8547521 },
-    { url = "https://files.pythonhosted.org/packages/b2/8d/8930e04a82f376b99db57d8d1c86bd35c06496e77f58f6b2cdb388cd12d9/ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913", size = 8149146 },
-    { url = "https://files.pythonhosted.org/packages/59/82/63d590c95025d526acc64803ab783f457ba15b3e16bea5bfb4b7ba9bf105/ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3", size = 8192701 },
-    { url = "https://files.pythonhosted.org/packages/70/f4/97e142f3c9cb2c886798821e31136b58a6095e068b5bf6a9667f45dcf70b/ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb", size = 7578485 },
-    { url = "https://files.pythonhosted.org/packages/fd/46/2b9addf3e3078c6d2c78135480f9dbf104257cfa6736d65154e9c7f64a34/ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764", size = 8768085 },
-    { url = "https://files.pythonhosted.org/packages/b5/bf/b7bcec679c67a74d4df5ecaa6e09352d4dd14a365a1d0ce76deb6f5d8a56/ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883", size = 9439095 },
-    { url = "https://files.pythonhosted.org/packages/cb/46/1a7bfa8f739116ec48d737d78d99b6e1c3c6307992b17b11bc8a44ee393f/ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199", size = 9060426 },
-    { url = "https://files.pythonhosted.org/packages/ad/6b/e82233a81554df12a3508a25a5068d005fb7b69b14cc4194237e7b4c5fcf/ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b", size = 10250216 },
-    { url = "https://files.pythonhosted.org/packages/21/77/9d9c536d8544d8b1b2fe1fcd5e3e190b946d91dc00a8956aa5fe88cb264b/ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45", size = 8797490 },
-    { url = "https://files.pythonhosted.org/packages/95/90/a614ec4ee32a61dcd76c5d77ef5c336acac447cf731d81313e42dcbc34ed/ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a", size = 8092448 },
-    { url = "https://files.pythonhosted.org/packages/1f/5b/d0a5ddf505593bacb52f386b0b92533dc2e87658a59ec55fe5b72890f1af/ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc", size = 7573842 },
-    { url = "https://files.pythonhosted.org/packages/da/4a/d6af0c924514ebc588474b5002ac9bc6cc0b2328d3633c1b10b0227032c1/ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed", size = 8358130 },
-    { url = "https://files.pythonhosted.org/packages/49/c4/3fbfb5a0020c9f67439dcef5a6e4f6a4f3430a059eaf40b624c00aa31bfa/ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa", size = 8842486 },
-    { url = "https://files.pythonhosted.org/packages/a5/e6/c18211dd3fad5a1da66a1bd7a00e3bdc7541fa997adeeb087c2147f1e18a/ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9", size = 7832464 },
-    { url = "https://files.pythonhosted.org/packages/95/b7/5b64aba350763aff321463e775f9daee9ad575750ebdb9f60f86f682f913/ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d", size = 8580070 },
-    { url = "https://files.pythonhosted.org/packages/fe/f1/3db1590be946c14d86ac0cc8422e5808500903592b7ca09a097e425b1dba/ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780", size = 7944828 },
-]
-
 [[package]]
 name = "s3transfer"
 version = "0.11.1"
@@ -6158,23 +4576,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 },
 ]
 
-[[package]]
-name = "selenium"
-version = "4.27.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "certifi" },
-    { name = "trio" },
-    { name = "trio-websocket" },
-    { name = "typing-extensions" },
-    { name = "urllib3", extra = ["socks"] },
-    { name = "websocket-client" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/44/8c/62c47c91072aa03af1c3b7d7f1c59b987db41c9fec0f158fb03a0da51aa6/selenium-4.27.1.tar.gz", hash = "sha256:5296c425a75ff1b44d0d5199042b36a6d1ef76c04fb775b97b40be739a9caae2", size = 973526 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a6/1e/5f1a5dd2a28528c4b3ec6e076b58e4c035810c805328f9936123283ca14e/selenium-4.27.1-py3-none-any.whl", hash = "sha256:b89b1f62b5cfe8025868556fe82360d6b649d464f75d2655cb966c8f8447ea18", size = 9707007 },
-]
-
 [[package]]
 name = "semantic-kernel"
 version = "1.18.2"
@@ -6266,12 +4667,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 },
 ]
 
-[[package]]
-name = "sgmllib3k"
-version = "1.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/9e/bd/3704a8c3e0942d711c1299ebf7b9091930adae6675d7c8f476a7ce48653c/sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9", size = 5750 }
-
 [[package]]
 name = "shapely"
 version = "2.0.6"
@@ -6310,18 +4705,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
 ]
 
-[[package]]
-name = "simple-websocket"
-version = "1.1.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "wsproto" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842 },
-]
-
 [[package]]
 name = "simsimd"
 version = "6.2.1"
@@ -6369,243 +4752,68 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/70/86/16e8d5b9bdd34f75c7515adfad249f394653131bd1a1366076cf6113e84b/simsimd-6.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:050f68cfa85f1fb2cfa156280928e42926e3977034b755023ce1315bf59e87ff", size = 302974 },
     { url = "https://files.pythonhosted.org/packages/02/09/3f4240f2b43957aa0d72a2203b2549c0326c7baf97b7f78c72d48d4cd3d2/simsimd-6.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67bb4b17e04919545f29c7b708faaccbe027f164f8b5c9f4328604fa8f5560ea", size = 227864 },
     { url = "https://files.pythonhosted.org/packages/07/4a/8c46806493c3a98025f01d81d9f55e0e574f11279c2ad77be919262ea9eb/simsimd-6.2.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3d6bffd999dbb36e606b065e0180365efac2606049c4f7818e4cba2d34c3678f", size = 432491 },
-    { url = "https://files.pythonhosted.org/packages/13/44/b56f207031405af52c6158c40e9f1121fe3a716d98946d9fa5919cf00266/simsimd-6.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:25adb244fb75dbf49af0d1bcac4ed4a3fef8e847d78449faa5595af0a3e20d61", size = 633061 },
-    { url = "https://files.pythonhosted.org/packages/4c/ad/241f87641af09a1789af8df559aa86b45218d087e09c37c2dd8c013819d6/simsimd-6.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b4542cee77e801a9c27370fc36ae271514fc0fb2ce14a35f8b25f47989e3d267", size = 468544 },
-    { url = "https://files.pythonhosted.org/packages/e2/3e/357aca7df85ed1092dfa50b91cf1b7c0df6f70b384a0e3798132dd824b5c/simsimd-6.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4f665228f8ff4911790b485e74b00fa9586a141dde6011970be71bb303b5a22f", size = 269133 },
-    { url = "https://files.pythonhosted.org/packages/f0/67/079ca2c58bbc5812802c6ac1b332a6ef889d73cf1188726f36edc27898f6/simsimd-6.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:783b4308f80ae00763b0eaa0dac26196958f9c2df60d35a0347ebd2f82ece46d", size = 344412 },
-    { url = "https://files.pythonhosted.org/packages/3c/f0/500c9002276259c17e3a6a13a7c7f84e5119602decadbf40429c978655b0/simsimd-6.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:95055e72cfe313c1c8694783bf8a631cc15673b3b775abef367e396d931db0b8", size = 389546 },
-    { url = "https://files.pythonhosted.org/packages/55/a2/d3f4c6aabba0430758367b3de5bbab59b979bf3525c039b882001f1d2ade/simsimd-6.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a98f2b383f51b4f4ee568a637fc7958a347fdae0bd184cff8faa8030b6454a39", size = 316912 },
-    { url = "https://files.pythonhosted.org/packages/f8/a3/2514189c3aaa1beb1714b36be86e2d3af7067c3c95152d78cc4cffff6d87/simsimd-6.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e474fd10ceb38e2c9f826108a7762f8ff7912974846d86f08c4e7b19cd35ed4", size = 670006 },
-    { url = "https://files.pythonhosted.org/packages/ef/23/dbf7c4aed7542260784dc7bc2056a4e5b6d716a14a9b40989d5c3096990a/simsimd-6.2.1-cp312-cp312-win32.whl", hash = "sha256:b2530ea44fffeab25e5752bec6a5991f30fbc430b04647980db5b195c0971d48", size = 55019 },
-    { url = "https://files.pythonhosted.org/packages/a0/d8/57304c2317822634abd475f5912584a3cfa13363740e9ec72c0622c894f1/simsimd-6.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:dc23283235d5b8f0373b95a547e26da2d7785647a5d0fa15c282fc8c49c0dcb0", size = 87133 },
-    { url = "https://files.pythonhosted.org/packages/3f/7b/ca333232a8bc87d1e846fa2feb9f0d4778500c30493726cb48f04551dfab/simsimd-6.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:5692ce7e56253178eea9dbd58191734918409b83d54b07cfdcecf868d0150a73", size = 60401 },
-]
-
-[[package]]
-name = "six"
-version = "1.17.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 },
-]
-
-[[package]]
-name = "smart-open"
-version = "7.1.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "wrapt" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/21/30/1f41c3d3b8cec82024b4b277bfd4e5b18b765ae7279eb9871fa25c503778/smart_open-7.1.0.tar.gz", hash = "sha256:a4f09f84f0f6d3637c6543aca7b5487438877a21360e7368ccf1f704789752ba", size = 72044 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7a/18/9a8d9f01957aa1f8bbc5676d54c2e33102d247e146c1a3679d3bd5cc2e3a/smart_open-7.1.0-py3-none-any.whl", hash = "sha256:4b8489bb6058196258bafe901730c7db0dcf4f083f316e97269c66f45502055b", size = 61746 },
-]
-
-[[package]]
-name = "sniffio"
-version = "1.3.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
-]
-
-[[package]]
-name = "snowballstemmer"
-version = "2.2.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 },
-]
-
-[[package]]
-name = "sortedcontainers"
-version = "2.4.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 },
-]
-
-[[package]]
-name = "soupsieve"
-version = "2.6"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
-]
-
-[[package]]
-name = "speechrecognition"
-version = "3.14.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/67/b91500f0796806659c37ba4da26750148ea98cd4e00d951facfdf4f440b3/speechrecognition-3.14.0.tar.gz", hash = "sha256:8f23d0125422fac358a05697ceffb5d7387a3f699fc2dcf829ee692fb15471c2", size = 32860450 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/5e/25/447b3a61afbc1d7e713ba56df0156aab1450442db752f1e6741d6a9f41df/SpeechRecognition-3.14.0-py3-none-any.whl", hash = "sha256:28303ae2b6abc13408963a91f838996f181f1c256936f94b8c021b51fcd4a3f5", size = 32852277 },
-]
-
-[[package]]
-name = "sphinx"
-version = "8.1.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "alabaster" },
-    { name = "babel" },
-    { name = "colorama", marker = "sys_platform == 'win32'" },
-    { name = "docutils" },
-    { name = "imagesize" },
-    { name = "jinja2" },
-    { name = "packaging" },
-    { name = "pygments" },
-    { name = "requests" },
-    { name = "snowballstemmer" },
-    { name = "sphinxcontrib-applehelp" },
-    { name = "sphinxcontrib-devhelp" },
-    { name = "sphinxcontrib-htmlhelp" },
-    { name = "sphinxcontrib-jsmath" },
-    { name = "sphinxcontrib-qthelp" },
-    { name = "sphinxcontrib-serializinghtml" },
-    { name = "tomli", marker = "python_full_version < '3.11'" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125 },
-]
-
-[[package]]
-name = "sphinx-autobuild"
-version = "2024.10.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "colorama" },
-    { name = "sphinx" },
-    { name = "starlette" },
-    { name = "uvicorn" },
-    { name = "watchfiles" },
-    { name = "websockets" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a5/2c/155e1de2c1ba96a72e5dba152c509a8b41e047ee5c2def9e9f0d812f8be7/sphinx_autobuild-2024.10.3.tar.gz", hash = "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1", size = 14023 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/18/c0/eba125db38c84d3c74717008fd3cb5000b68cd7e2cbafd1349c6a38c3d3b/sphinx_autobuild-2024.10.3-py3-none-any.whl", hash = "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa", size = 11908 },
-]
-
-[[package]]
-name = "sphinx-copybutton"
-version = "0.5.2"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "sphinx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343 },
-]
-
-[[package]]
-name = "sphinx-design"
-version = "0.6.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "sphinx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/2b/69/b34e0cb5336f09c6866d53b4a19d76c227cdec1bbc7ac4de63ca7d58c9c7/sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632", size = 2193689 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/c6/43/65c0acbd8cc6f50195a3a1fc195c404988b15c67090e73c7a41a9f57d6bd/sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c", size = 2215338 },
-]
-
-[[package]]
-name = "sphinxcontrib-apidoc"
-version = "0.5.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pbr" },
-    { name = "sphinx" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/52/8c/a4fe93b51a1026c217731337cfe50569b8521d3e254dd451126bed208cd8/sphinxcontrib-apidoc-0.5.0.tar.gz", hash = "sha256:65efcd92212a5f823715fb95ee098b458a6bb09a5ee617d9ed3dead97177cd55", size = 16117 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/1c/35/453ba8b0f407b9b86520eba5122fe28e87230266cfae9524a623b524485e/sphinxcontrib_apidoc-0.5.0-py3-none-any.whl", hash = "sha256:c671d644d6dc468be91b813dcddf74d87893bff74fe8f1b8b01b69408f0fb776", size = 8603 },
-]
-
-[[package]]
-name = "sphinxcontrib-applehelp"
-version = "2.0.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 },
+    { url = "https://files.pythonhosted.org/packages/13/44/b56f207031405af52c6158c40e9f1121fe3a716d98946d9fa5919cf00266/simsimd-6.2.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:25adb244fb75dbf49af0d1bcac4ed4a3fef8e847d78449faa5595af0a3e20d61", size = 633061 },
+    { url = "https://files.pythonhosted.org/packages/4c/ad/241f87641af09a1789af8df559aa86b45218d087e09c37c2dd8c013819d6/simsimd-6.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b4542cee77e801a9c27370fc36ae271514fc0fb2ce14a35f8b25f47989e3d267", size = 468544 },
+    { url = "https://files.pythonhosted.org/packages/e2/3e/357aca7df85ed1092dfa50b91cf1b7c0df6f70b384a0e3798132dd824b5c/simsimd-6.2.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4f665228f8ff4911790b485e74b00fa9586a141dde6011970be71bb303b5a22f", size = 269133 },
+    { url = "https://files.pythonhosted.org/packages/f0/67/079ca2c58bbc5812802c6ac1b332a6ef889d73cf1188726f36edc27898f6/simsimd-6.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:783b4308f80ae00763b0eaa0dac26196958f9c2df60d35a0347ebd2f82ece46d", size = 344412 },
+    { url = "https://files.pythonhosted.org/packages/3c/f0/500c9002276259c17e3a6a13a7c7f84e5119602decadbf40429c978655b0/simsimd-6.2.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:95055e72cfe313c1c8694783bf8a631cc15673b3b775abef367e396d931db0b8", size = 389546 },
+    { url = "https://files.pythonhosted.org/packages/55/a2/d3f4c6aabba0430758367b3de5bbab59b979bf3525c039b882001f1d2ade/simsimd-6.2.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a98f2b383f51b4f4ee568a637fc7958a347fdae0bd184cff8faa8030b6454a39", size = 316912 },
+    { url = "https://files.pythonhosted.org/packages/f8/a3/2514189c3aaa1beb1714b36be86e2d3af7067c3c95152d78cc4cffff6d87/simsimd-6.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2e474fd10ceb38e2c9f826108a7762f8ff7912974846d86f08c4e7b19cd35ed4", size = 670006 },
+    { url = "https://files.pythonhosted.org/packages/ef/23/dbf7c4aed7542260784dc7bc2056a4e5b6d716a14a9b40989d5c3096990a/simsimd-6.2.1-cp312-cp312-win32.whl", hash = "sha256:b2530ea44fffeab25e5752bec6a5991f30fbc430b04647980db5b195c0971d48", size = 55019 },
+    { url = "https://files.pythonhosted.org/packages/a0/d8/57304c2317822634abd475f5912584a3cfa13363740e9ec72c0622c894f1/simsimd-6.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:dc23283235d5b8f0373b95a547e26da2d7785647a5d0fa15c282fc8c49c0dcb0", size = 87133 },
+    { url = "https://files.pythonhosted.org/packages/3f/7b/ca333232a8bc87d1e846fa2feb9f0d4778500c30493726cb48f04551dfab/simsimd-6.2.1-cp312-cp312-win_arm64.whl", hash = "sha256:5692ce7e56253178eea9dbd58191734918409b83d54b07cfdcecf868d0150a73", size = 60401 },
 ]
 
 [[package]]
-name = "sphinxcontrib-devhelp"
-version = "2.0.0"
+name = "six"
+version = "1.17.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 },
+    { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 },
 ]
 
 [[package]]
-name = "sphinxcontrib-htmlhelp"
-version = "2.1.0"
+name = "smart-open"
+version = "7.1.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 },
+dependencies = [
+    { name = "wrapt" },
 ]
-
-[[package]]
-name = "sphinxcontrib-jsmath"
-version = "1.0.1"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 }
+sdist = { url = "https://files.pythonhosted.org/packages/21/30/1f41c3d3b8cec82024b4b277bfd4e5b18b765ae7279eb9871fa25c503778/smart_open-7.1.0.tar.gz", hash = "sha256:a4f09f84f0f6d3637c6543aca7b5487438877a21360e7368ccf1f704789752ba", size = 72044 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 },
+    { url = "https://files.pythonhosted.org/packages/7a/18/9a8d9f01957aa1f8bbc5676d54c2e33102d247e146c1a3679d3bd5cc2e3a/smart_open-7.1.0-py3-none-any.whl", hash = "sha256:4b8489bb6058196258bafe901730c7db0dcf4f083f316e97269c66f45502055b", size = 61746 },
 ]
 
 [[package]]
-name = "sphinxcontrib-qthelp"
-version = "2.0.0"
+name = "sniffio"
+version = "1.3.1"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 },
+    { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
 ]
 
 [[package]]
-name = "sphinxcontrib-serializinghtml"
-version = "2.0.0"
+name = "soupsieve"
+version = "2.6"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 }
+sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 },
+    { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
 ]
 
 [[package]]
-name = "sphinxext-rediraffe"
-version = "0.2.7"
+name = "speechrecognition"
+version = "3.14.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "sphinx" },
+    { name = "typing-extensions" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/1f/b4/e5fbb493f796430230189a1ce5f9beff1ac1b98619fc71ed35deca6059a5/sphinxext-rediraffe-0.2.7.tar.gz", hash = "sha256:651dcbfae5ffda9ffd534dfb8025f36120e5efb6ea1a33f5420023862b9f725d", size = 8735 }
+sdist = { url = "https://files.pythonhosted.org/packages/ce/67/b91500f0796806659c37ba4da26750148ea98cd4e00d951facfdf4f440b3/speechrecognition-3.14.0.tar.gz", hash = "sha256:8f23d0125422fac358a05697ceffb5d7387a3f699fc2dcf829ee692fb15471c2", size = 32860450 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/76/4f/c8797e796199e55cf6c8979ecdf5f4b09b81e93f87b3193c759faea63263/sphinxext_rediraffe-0.2.7-py3-none-any.whl", hash = "sha256:9e430a52d4403847f4ffb3a8dd6dfc34a9fe43525305131f52ed899743a5fd8c", size = 8267 },
-]
-
-[[package]]
-name = "spider-client"
-version = "0.0.27"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "requests" },
+    { url = "https://files.pythonhosted.org/packages/5e/25/447b3a61afbc1d7e713ba56df0156aab1450442db752f1e6741d6a9f41df/SpeechRecognition-3.14.0-py3-none-any.whl", hash = "sha256:28303ae2b6abc13408963a91f838996f181f1c256936f94b8c021b51fcd4a3f5", size = 32852277 },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/70/fc/a2a4cc112c467f89921328d005c0ac2df9c81f62c8a6d445f747252f5856/spider-client-0.0.27.tar.gz", hash = "sha256:c3feaf5c491bd9a6c509efa0c8789452497073d9f68e70fc90e7626a6a8365aa", size = 5755 }
 
 [[package]]
 name = "sqlalchemy"
@@ -6644,11 +4852,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/3b/36/59cc97c365f2f79ac9f3f51446cae56dfd82c4f2dd98497e6be6de20fb91/SQLAlchemy-2.0.37-py3-none-any.whl", hash = "sha256:a8998bf9f8658bd3839cbc44ddbe982955641863da0c1efe5b00c1ab4f5c16b1", size = 1894113 },
 ]
 
-[package.optional-dependencies]
-asyncio = [
-    { name = "greenlet" },
-]
-
 [[package]]
 name = "sqlmodel"
 version = "0.0.22"
@@ -6721,15 +4924,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/59/9a/e466a1b887a1441141e52dbcc98152f013d85076576da6eed2357f2016ae/statsmodels-0.14.4-cp312-cp312-win_amd64.whl", hash = "sha256:7f7917a51766b4e074da283c507a25048ad29a18e527207883d73535e0dc6184", size = 9823866 },
 ]
 
-[[package]]
-name = "striprtf"
-version = "0.0.26"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/25/20/3d419008265346452d09e5dadfd5d045b64b40d8fc31af40588e6c76997a/striprtf-0.0.26.tar.gz", hash = "sha256:fdb2bba7ac440072d1c41eab50d8d74ae88f60a8b6575c6e2c7805dc462093aa", size = 6258 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a3/cf/0fea4f4ba3fc2772ac2419278aa9f6964124d4302117d61bc055758e000c/striprtf-0.0.26-py3-none-any.whl", hash = "sha256:8c8f9d32083cdc2e8bfb149455aa1cc5a4e0a035893bedc75db8b73becb3a1bb", size = 6914 },
-]
-
 [[package]]
 name = "sympy"
 version = "1.13.1"
@@ -6742,12 +4936,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177 },
 ]
 
-[[package]]
-name = "syncer"
-version = "2.0.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/8d/dd/d4dd75843692690d81f0a4b929212a1614b25d4896aa7c72f4c3546c7e3d/syncer-2.0.3.tar.gz", hash = "sha256:4340eb54b54368724a78c5c0763824470201804fe9180129daf3635cb500550f", size = 11512 }
-
 [[package]]
 name = "tabulate"
 version = "0.9.0"
@@ -6757,20 +4945,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 },
 ]
 
-[[package]]
-name = "tavily-python"
-version = "0.5.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "httpx" },
-    { name = "requests" },
-    { name = "tiktoken" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ca/50/7f4acafe72ffd10d3578ddec76f993af5af81504bc7315ea54862f2705b9/tavily_python-0.5.0.tar.gz", hash = "sha256:2c60b88203b630e1b37fc711913a1090ced6719b3f21089f25ec06e9e1602822", size = 16455 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/90/99/05776f7150a5b3f8d853377144a3a634131964c0fce38307537674a9a674/tavily_python-0.5.0-py3-none-any.whl", hash = "sha256:e874f6a04a56cdda80a505fe0b4f5d61d25372bd52a83e6773926fb297dcaa29", size = 14361 },
-]
-
 [[package]]
 name = "tenacity"
 version = "9.0.0"
@@ -6780,77 +4954,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b6/cb/b86984bed139586d01532a587464b5805f12e397594f19f931c4c2fbfa61/tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539", size = 28169 },
 ]
 
-[[package]]
-name = "text-unidecode"
-version = "1.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154 },
-]
-
-[[package]]
-name = "textual"
-version = "1.0.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "markdown-it-py", extra = ["linkify", "plugins"] },
-    { name = "platformdirs" },
-    { name = "rich" },
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/1f/b6/59b1de04bb4dca0f21ed7ba0b19309ed7f3f5de4396edf20cc2855e53085/textual-1.0.0.tar.gz", hash = "sha256:bec9fe63547c1c552569d1b75d309038b7d456c03f86dfa3706ddb099b151399", size = 1532733 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ac/bb/5fb6656c625019cd653d5215237d7cd6e0b12e7eae4195c3d1c91b2136fc/textual-1.0.0-py3-none-any.whl", hash = "sha256:2d4a701781c05104925e463ae370c630567c70c2880e92ab838052e3e23c986f", size = 660456 },
-]
-
-[[package]]
-name = "textual-dev"
-version = "1.7.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "click" },
-    { name = "msgpack" },
-    { name = "textual" },
-    { name = "textual-serve" },
-    { name = "typing-extensions" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/a1/d3/ed0b20f6de0af1b7062c402d59d256029c0daa055ad9e04c27471b450cdd/textual_dev-1.7.0.tar.gz", hash = "sha256:bf1a50eaaff4cd6a863535dd53f06dbbd62617c371604f66f56de3908220ccd5", size = 25935 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/50/4b/3c1eb9cbc39f2f28d27e10ef2fe42bfe0cf3c2f8445a454c124948d6169b/textual_dev-1.7.0-py3-none-any.whl", hash = "sha256:a93a846aeb6a06edb7808504d9c301565f7f4bf2e7046d56583ed755af356c8d", size = 27221 },
-]
-
-[[package]]
-name = "textual-imageview"
-version = "0.1.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "pillow" },
-    { name = "rich" },
-    { name = "textual" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/4b/31/3d8a517bd8694ee0d70fd260fbc20590f00a5fcde6ca1ce2edb174c000ac/textual_imageview-0.1.1.tar.gz", hash = "sha256:4299d8ed677db0adb8fe945687470cf1421dcafd2a5dddab54b6ee8ef2ab3320", size = 3232614 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/43/56/c0514dcfdb2b67333bf4e653ca9cf0fda51004932d3b246bf835376cbaba/textual_imageview-0.1.1-py3-none-any.whl", hash = "sha256:335c8043e2f1f735b1b2ec1753a743d6762578175cd2cedae3ce67e2694800a4", size = 8875 },
-]
-
-[[package]]
-name = "textual-serve"
-version = "1.1.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "aiohttp" },
-    { name = "aiohttp-jinja2" },
-    { name = "jinja2" },
-    { name = "rich" },
-    { name = "textual" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/18/6c/57248070f525ea8a9a02d9f58dc2747c609b615b0bda1306aaeb80a233bd/textual_serve-1.1.1.tar.gz", hash = "sha256:71c662472c462e5e368defc660ee6e8eae3bfda88ca40c050c55474686eb0c54", size = 445957 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/07/a9/01d35770fde8d889e1fe28b726188cf28801e57afd369c614cd2bc100ee4/textual_serve-1.1.1-py3-none-any.whl", hash = "sha256:568782f1c0e60e3f7039d9121e1cb5c2f4ca1aaf6d6bd7aeb833d5763a534cb2", size = 445034 },
-]
-
 [[package]]
 name = "threadpoolctl"
 version = "3.5.0"
@@ -6890,36 +4993,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 },
 ]
 
-[[package]]
-name = "tinysegmenter"
-version = "0.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/17/82/86982e4b6d16e4febc79c2a1d68ee3b707e8a020c5d2bc4af8052d0f136a/tinysegmenter-0.3.tar.gz", hash = "sha256:ed1f6d2e806a4758a73be589754384cbadadc7e1a414c81a166fc9adf2d40c6d", size = 16893 }
-
-[[package]]
-name = "tldextract"
-version = "5.1.3"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "filelock" },
-    { name = "idna" },
-    { name = "requests" },
-    { name = "requests-file" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/4a/4f/eee4bebcbad25a798bf55601d3a4aee52003bebcf9e55fce08b91ca541a9/tldextract-5.1.3.tar.gz", hash = "sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338", size = 125033 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/c6/86/aebe15fa40a992c446be5cf14e70e58a251277494c14d26bdbcff0e658fd/tldextract-5.1.3-py3-none-any.whl", hash = "sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75", size = 104923 },
-]
-
-[[package]]
-name = "tokenize-rt"
-version = "6.1.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/6b/0a/5854d8ced8c1e00193d1353d13db82d7f813f99bd5dcb776ce3e2a4c0d19/tokenize_rt-6.1.0.tar.gz", hash = "sha256:e8ee836616c0877ab7c7b54776d2fefcc3bde714449a206762425ae114b53c86", size = 5506 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/87/ba/576aac29b10dfa49a6ce650001d1bb31f81e734660555eaf144bfe5b8995/tokenize_rt-6.1.0-py2.py3-none-any.whl", hash = "sha256:d706141cdec4aa5f358945abe36b911b8cbdc844545da99e811250c0cee9b6fc", size = 6015 },
-]
-
 [[package]]
 name = "tokenizers"
 version = "0.21.0"
@@ -6974,15 +5047,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
 ]
 
-[[package]]
-name = "tomli-w"
-version = "1.2.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675 },
-]
-
 [[package]]
 name = "torch"
 version = "2.5.1"
@@ -6992,21 +5056,21 @@ dependencies = [
     { name = "fsspec" },
     { name = "jinja2" },
     { name = "networkx" },
-    { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
-    { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
     { name = "setuptools", marker = "python_full_version >= '3.12'" },
     { name = "sympy" },
-    { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
     { name = "typing-extensions" },
 ]
 wheels = [
@@ -7047,7 +5111,7 @@ name = "tqdm"
 version = "4.67.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "colorama", marker = "platform_system == 'Windows'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 }
 wheels = [
@@ -7090,44 +5154,12 @@ torch = [
     { name = "torch" },
 ]
 
-[[package]]
-name = "trio"
-version = "0.28.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "attrs" },
-    { name = "cffi", marker = "(implementation_name != 'pypy' and os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (implementation_name != 'pypy' and os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" },
-    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
-    { name = "idna" },
-    { name = "outcome" },
-    { name = "sniffio" },
-    { name = "sortedcontainers" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/b3/73/57efab729506a8d4b89814f1e356ec8f3369de0ed4fd7e7616974d09646d/trio-0.28.0.tar.gz", hash = "sha256:4e547896fe9e8a5658e54e4c7c5fa1db748cbbbaa7c965e7d40505b928c73c05", size = 580318 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/b4/04/9954a59e1fb6732f5436225c9af963811d7b24ea62a8bf96991f2cb8c26e/trio-0.28.0-py3-none-any.whl", hash = "sha256:56d58977acc1635735a96581ec70513cc781b8b6decd299c487d3be2a721cd94", size = 486317 },
-]
-
-[[package]]
-name = "trio-websocket"
-version = "0.11.1"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
-    { name = "trio" },
-    { name = "wsproto" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/dd/36/abad2385853077424a11b818d9fd8350d249d9e31d583cb9c11cd4c85eda/trio-websocket-0.11.1.tar.gz", hash = "sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f", size = 26511 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/48/be/a9ae5f50cad5b6f85bd2574c2c923730098530096e170c1ce7452394d7aa/trio_websocket-0.11.1-py3-none-any.whl", hash = "sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638", size = 17408 },
-]
-
 [[package]]
 name = "triton"
 version = "3.1.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "filelock", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "filelock", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/98/29/69aa56dc0b2eb2602b553881e34243475ea2afd9699be042316842788ff5/triton-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0dd10a925263abbe9fa37dcde67a5e9b2383fc269fdf59f5657cac38c5d1d8", size = 209460013 },
@@ -7150,85 +5182,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 },
 ]
 
-[[package]]
-name = "types-aiofiles"
-version = "24.1.0.20241221"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/f984b9ddc7eecdf31e683e692d933f3672276ed95aad6adb9aea9ecbdc29/types_aiofiles-24.1.0.20241221.tar.gz", hash = "sha256:c40f6c290b0af9e902f7f3fa91213cf5bb67f37086fb21dc0ff458253586ad55", size = 14081 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/ff/da/77902220df98ce920444cf3611fa0b1cf0dc2cfa5a137c55e93829aa458e/types_aiofiles-24.1.0.20241221-py3-none-any.whl", hash = "sha256:11d4e102af0627c02e8c1d17736caa3c39de1058bea37e2f4de6ef11a5b652ab", size = 14162 },
-]
-
-[[package]]
-name = "types-docker"
-version = "7.1.0.20241229"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "types-requests" },
-    { name = "urllib3" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/00/4b/7ca6c1fe916ef4c71f145234902bb4da074e410d9cc0bd72572790c3f06d/types_docker-7.1.0.20241229.tar.gz", hash = "sha256:d968f164bb02f934bc2f178515dd4b3c8b2b4e371a9400ec440247c09c139545", size = 29032 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/e4/32/8a1c95566816fef8f7b2407d25981cf0d3ecf2f226ed0ab3a34969994ab7/types_docker-7.1.0.20241229-py3-none-any.whl", hash = "sha256:b760745a6cb0351a19108c0b76e2a43ebc05a686f6c3ec9bc1a991ff9f1cc353", size = 43650 },
-]
-
-[[package]]
-name = "types-pillow"
-version = "10.2.0.20240822"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/18/4a/4495264dddaa600d65d68bcedb64dcccf9d9da61adff51f7d2ffd8e4c9ce/types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3", size = 35389 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/66/23/e81a5354859831fcf54d488d33b80ba6133ea84f874a9c0ec40a4881e133/types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d", size = 54354 },
-]
-
-[[package]]
-name = "types-protobuf"
-version = "5.29.1.20241207"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/70/89/b661a447139f665ccea8e39bfdd52a92f803df4b5de0e6001a3537feaacb/types_protobuf-5.29.1.20241207.tar.gz", hash = "sha256:2ebcadb8ab3ef2e3e2f067e0882906d64ba0dc65fc5b0fd7a8b692315b4a0be9", size = 59190 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/7e/6e/cdf152187019d6f6d04066b23e48659d961b527e9c6d43b48459d160e332/types_protobuf-5.29.1.20241207-py3-none-any.whl", hash = "sha256:92893c42083e9b718c678badc0af7a9a1307b92afe1599e5cba5f3d35b668b2f", size = 73902 },
-]
-
-[[package]]
-name = "types-python-dateutil"
-version = "2.9.0.20241206"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 },
-]
-
-[[package]]
-name = "types-pytz"
-version = "2024.2.0.20241221"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/54/26/516311b02b5a215e721155fb65db8a965d061372e388d6125ebce8d674b0/types_pytz-2024.2.0.20241221.tar.gz", hash = "sha256:06d7cde9613e9f7504766a0554a270c369434b50e00975b3a4a0f6eed0f2c1a9", size = 10213 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/74/db/c92ca6920cccd9c2998b013601542e2ac5e59bc805bcff94c94ad254b7df/types_pytz-2024.2.0.20241221-py3-none-any.whl", hash = "sha256:8fc03195329c43637ed4f593663df721fef919b60a969066e22606edf0b53ad5", size = 10008 },
-]
-
-[[package]]
-name = "types-requests"
-version = "2.32.0.20241016"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "urllib3" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/fa/3c/4f2a430c01a22abd49a583b6b944173e39e7d01b688190a5618bd59a2e22/types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95", size = 18065 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/d7/01/485b3026ff90e5190b5e24f1711522e06c79f4a56c8f4b95848ac072e20f/types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747", size = 15836 },
-]
-
-[[package]]
-name = "types-tabulate"
-version = "0.9.0.20241207"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/3f/43/16030404a327e4ff8c692f2273854019ed36718667b2993609dc37d14dd4/types_tabulate-0.9.0.20241207.tar.gz", hash = "sha256:ac1ac174750c0a385dfd248edc6279fa328aaf4ea317915ab879a2ec47833230", size = 8195 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/5e/86/a9ebfd509cbe74471106dffed320e208c72537f9aeb0a55eaa6b1b5e4d17/types_tabulate-0.9.0.20241207-py3-none-any.whl", hash = "sha256:b8dad1343c2a8ba5861c5441370c3e35908edd234ff036d4298708a1d4cf8a85", size = 8307 },
-]
-
 [[package]]
 name = "typing-extensions"
 version = "4.12.2"
@@ -7260,15 +5213,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 },
 ]
 
-[[package]]
-name = "uc-micro-py"
-version = "1.0.3"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229 },
-]
-
 [[package]]
 name = "umap-learn"
 version = "0.5.7"
@@ -7286,21 +5230,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/3c/8f/671c0e1f2572ba625cbcc1faeba9435e00330c3d6962858711445cf1e817/umap_learn-0.5.7-py3-none-any.whl", hash = "sha256:6a7e0be2facfa365a5ed6588447102bdbef32a0ef449535c25c97ea7e680073c", size = 88815 },
 ]
 
-[[package]]
-name = "uptrace"
-version = "1.27.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "opentelemetry-api" },
-    { name = "opentelemetry-exporter-otlp" },
-    { name = "opentelemetry-instrumentation" },
-    { name = "opentelemetry-sdk" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/f3/89/ba1df9328e4bd4b440ac6979e20ec8c63a26f6400598e806cc9dfef764f4/uptrace-1.27.0.tar.gz", hash = "sha256:983f783b2f4303d1d2bdfaf6ace1b7a5f072af47f78a7815f82c51fcf5099cac", size = 7633 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/77/00/054ac30e9e8312c3c79371c495dd570865eab2a05bfcd640f6242d460c8b/uptrace-1.27.0-py3-none-any.whl", hash = "sha256:d5473efa33c34e3d5738d32d19301dbf004d4e19598c658f2fa9f3f09458f630", size = 8627 },
-]
-
 [[package]]
 name = "uritemplate"
 version = "4.1.1"
@@ -7319,11 +5248,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 },
 ]
 
-[package.optional-dependencies]
-socks = [
-    { name = "pysocks" },
-]
-
 [[package]]
 name = "usearch"
 version = "2.16.9"
@@ -7377,30 +5301,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/26/59/fddd9df489fe27f492cc97626e03663fb3b9b6ef7ce8597a7cdc5f2cbbad/uvicorn-0.25.0-py3-none-any.whl", hash = "sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c", size = 60303 },
 ]
 
-[[package]]
-name = "watchfiles"
-version = "0.20.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "anyio" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/ef/48/02d2d2cbf54e134810b2cb40ac79fdb8ce08476184536a4764717a7bc9f4/watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019", size = 37041 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/4d/db/899832e11fef2d468bf8b3c1c13289b1db4cb7c3410bb2a9612a52fc8b22/watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9", size = 417357 },
-    { url = "https://files.pythonhosted.org/packages/9f/1a/85c914e4db62a3f8197daa98a271ea380a5d200a8d3058bd9f417752bc26/watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458", size = 407258 },
-    { url = "https://files.pythonhosted.org/packages/25/ae/b7bddad421af5e33079a2ce639aa58837b715a2da98df16e25ecd310af52/watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490", size = 1331327 },
-    { url = "https://files.pythonhosted.org/packages/21/e5/b080cec4e841b1cf338ccbd958cf3232ad1691a590653b2d124b5c79cf6b/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa", size = 1301371 },
-    { url = "https://files.pythonhosted.org/packages/05/a0/2fb2c36730995a6b3f060187195dc08ad9ceee67426bdca8a4296024071c/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38", size = 1302438 },
-    { url = "https://files.pythonhosted.org/packages/13/ea/d11971958ae703cfe443b21f672169cb8bc12dbec5781b910633fa2186ec/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0", size = 1410655 },
-    { url = "https://files.pythonhosted.org/packages/6b/81/3f922f3ede53ca9c0b4095f63688ffeea19a49592d0ac62db1eb9632b1e3/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95", size = 1494222 },
-    { url = "https://files.pythonhosted.org/packages/e1/46/c9d5ee4871b187d291d62e61c41f9a4d67d4866a89704b0ad16b6949e9bd/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf", size = 1294171 },
-    { url = "https://files.pythonhosted.org/packages/59/5e/6b64e3bf9fd4422250f3c716d992dd76dbe55e6fa1e7ebaf2bf88f389707/watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db", size = 1462256 },
-    { url = "https://files.pythonhosted.org/packages/11/c0/75f5a71ac24118ab11bd898e0114cedc72b25924ff2d960d473bddb4ec6e/watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164", size = 1461725 },
-    { url = "https://files.pythonhosted.org/packages/91/d4/0c0fdcc4293ad1b73db54896fa0de4b37439ae4f25971b5eb1708dd04f9a/watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5", size = 268193 },
-    { url = "https://files.pythonhosted.org/packages/87/79/098b1b1fcb6de16149d23283a2ab5dadce6a06b864e7a182d231f57a1f9e/watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3", size = 276723 },
-    { url = "https://files.pythonhosted.org/packages/3f/82/45dddf4f5bf8b73ba27382cebb2bb3c0ee922c7ef77d936b86276aa39dca/watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c", size = 265344 },
-]
-
 [[package]]
 name = "wcwidth"
 version = "0.2.13"
@@ -7410,15 +5310,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 },
 ]
 
-[[package]]
-name = "websocket-client"
-version = "1.8.0"
-source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 },
-]
-
 [[package]]
 name = "websockets"
 version = "14.1"
@@ -7479,16 +5370,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498 },
 ]
 
-[[package]]
-name = "wikipedia"
-version = "1.4.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "beautifulsoup4" },
-    { name = "requests" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/67/35/25e68fbc99e672127cc6fbb14b8ec1ba3dfef035bf1e4c90f78f24a80b7d/wikipedia-1.4.0.tar.gz", hash = "sha256:db0fad1829fdd441b1852306e9856398204dc0786d2996dd2e0c8bb8e26133b2", size = 27748 }
-
 [[package]]
 name = "win32-setctime"
 version = "1.2.0"
@@ -7540,18 +5421,6 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594 },
 ]
 
-[[package]]
-name = "wsproto"
-version = "1.2.0"
-source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "h11" },
-]
-sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425 }
-wheels = [
-    { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226 },
-]
-
 [[package]]
 name = "xlsxwriter"
 version = "3.2.0"

From efb8fbb660fa65949cad9436e4932c2af202ce01 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 10:11:43 -0800
Subject: [PATCH 065/110] propogate cancellation

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index fbbd69adc13e..33f0c7a5471d 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -371,8 +371,8 @@ void StartCore()
 
             try
             {
-                _readTask = Task.Run(RunReadPump, CancellationToken.None);
-                _writeTask = Task.Run(RunWritePump, CancellationToken.None);
+                _readTask = Task.Run(RunReadPump, cancellationToken);
+                _writeTask = Task.Run(RunWritePump, cancellationToken);
             }
             finally
             {

From 954aad2e34bf5837b9964fd3d3f3346a13c85afd Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 11:10:26 -0800
Subject: [PATCH 066/110] fix mixup in topic

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 25f51b4506d0..af87ce12d644 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -297,7 +297,10 @@ private string SetTopic(string? topic = null, string? source = null, string? key
         {
             topic = this.AgentId.Type + "." + this.AgentId.Key;
         }
-        topic = topic + "." + source + "." + key;
+        else
+        {
+            topic = topic + "." + source + "." + key;
+        }
         return topic;
     }
 

From eaab0cd9440306d031feb3536f5e012c3f93c1f0 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 11:13:31 -0800
Subject: [PATCH 067/110] undo unexpected change

---
 README.md | 1 +
 1 file changed, 1 insertion(+)

diff --git a/README.md b/README.md
index a85b33992373..179067fe9106 100644
--- a/README.md
+++ b/README.md
@@ -63,6 +63,7 @@ from autogen_agentchat.teams import RoundRobinGroupChat
 from autogen_agentchat.ui import Console
 from autogen_ext.models.openai import OpenAIChatCompletionClient
 from autogen_ext.agents.web_surfer import MultimodalWebSurfer
+
 async def main() -> None:
     model_client = OpenAIChatCompletionClient(model="gpt-4o")
     assistant = AssistantAgent("assistant", model_client)

From ae81b19ff5765ca992d8d6c117e428fcf531a048 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 11:29:50 -0800
Subject: [PATCH 068/110] need to Connect() the worker process

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs                 | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index afe95c747a93..294ffbf48eac 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -145,13 +145,13 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
             _logger.LogWarning(exception, "Error removing worker from registry.");
         }
     }
-    internal Task ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
+    internal async Task ConnectToWorkerProcess(IAsyncStreamReader<Message> requestStream, IServerStreamWriter<Message> responseStream, ServerCallContext context)
     {
         _logger.LogInformation("Received new connection from {Peer}.", context.Peer);
         var workerProcess = new GrpcWorkerConnection(this, requestStream, responseStream, context);
+        await workerProcess.Connect().ConfigureAwait(false);
         _workers[workerProcess] = workerProcess;
         _workersByConnection[context.Peer] = workerProcess;
-        return workerProcess.Completion;
     }
     internal async Task SendMessageAsync(GrpcWorkerConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {

From 17618c08a7016e0b59c338425b2bc36b044aed98 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 11:51:14 -0800
Subject: [PATCH 069/110] TryGetValue instead of index

---
 .../Services/Orleans/RegistryGrain.cs         | 21 ++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index c3fbd58dbd43..3145b8f6b87d 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -22,11 +22,22 @@ public override Task OnActivateAsync(CancellationToken cancellationToken)
     public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType)
     {
         // get all agent types that are subscribed to the topic
-        var subscribedAgents = state.State.TopicToAgentTypesMap[topic];
-        // get all agent types that are handling the event
-        var handlingAgents = state.State.EventsToAgentTypesMap[eventType];
-        // return the intersection of the two sets
-        return new(subscribedAgents.Intersect(handlingAgents).ToList());
+        if(state.State.TopicToAgentTypesMap.TryGetValue(topic, out var subscribedAgentTypes))
+        {
+            // get all agent types that are handling the event
+            if(state.State.EventsToAgentTypesMap.TryGetValue(eventType, out var handlingAgents))
+            {
+                // return the intersection of the two sets
+                return new(subscribedAgentTypes.Intersect(handlingAgents).ToList());
+            }
+            else
+            {
+                return new();
+            }
+        } else
+        {
+            return new();
+        }
     }
     public ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId)
     {

From 6c8bcb01135746cbfebd2188bfcd7a6c6e841ff9 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 12:34:15 -0800
Subject: [PATCH 070/110] remove incorrect test, fix some null values, ensure
 subject/source is set correctly

---
 .../Core.Grpc/GrpcAgentWorker.cs              |  9 +++++++--
 .../Core/MessageExtensions.cs                 |  9 ++++++++-
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs |  3 ++-
 .../AgentGrpcTests.cs                         | 20 -------------------
 4 files changed, 17 insertions(+), 24 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 33f0c7a5471d..c63c4efc2c8c 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -96,7 +96,12 @@ private async Task RunReadPump()
                             }
                             foreach (var a in agents)
                             {
-                                var agent = GetOrActivateAgent(new AgentId { Type = a.Name, Key = item.GetSubject() });
+                                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;
@@ -191,7 +196,7 @@ private Agent GetOrActivateAgent(AgentId agentId)
         {
             if (_agentTypes.TryGetValue(agentId.Type, out var agentType))
             {
-                agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType, this);
+                agent = (Agent)ActivatorUtilities.CreateInstance(ServiceProvider, agentType);
                 Agent.Initialize(this, agent);
                 _agents.TryAdd((agentId.Type, agentId.Key), agent);
             }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
index 5ac9d43cf092..e5fbb4c99025 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
@@ -55,7 +55,14 @@ public static CloudEvent ToCloudEvent<T>(this T message, string key, string topi
     /// <summary>
     public static string GetSubject(this CloudEvent cloudEvent)
     {
-        return cloudEvent.Attributes["subject"].CeString;
+        if(cloudEvent.Attributes.TryGetValue("subject", out var value))
+        {
+            return value.CeString;
+        }
+        else
+        {
+            return string.Empty;
+        }
     }
 
     /// <summary>
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 294ffbf48eac..c2257cbc2b08 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -216,7 +216,8 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
         //intentionally blocking
         var targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
-        if (targetAgentTypes.Count == 0)
+        //verify targetAgentTypes is not null
+        if (targetAgentTypes is null || targetAgentTypes.Count == 0)
         {
             _logger.LogWarning("No agents found registered for event {Event}.", evt);
         }
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 6fd2d495d7a8..9a9b16669330 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -153,26 +153,6 @@ public async Task InvokeCorrectHandler()
         agent.ReceivedItems[1].Should().Be(42);
     }
 
-    [Fact]
-    public async Task DelegateMessageToTestAgentAsync()
-    {
-        var client = _fixture.Client.Services.GetRequiredService<Client>();
-        await client.PublishMessageAsync(new TextMessage()
-        {
-            Source = nameof(DelegateMessageToTestAgentAsync),
-            TextMessage_ = "buffer"
-        }, token: CancellationToken.None);
-
-        // wait for 10 seconds
-        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));
-        while (!TestAgent.ReceivedMessages.ContainsKey(nameof(DelegateMessageToTestAgentAsync)) && !cts.Token.IsCancellationRequested)
-        {
-            await Task.Delay(100);
-        }
-
-        TestAgent.ReceivedMessages[nameof(DelegateMessageToTestAgentAsync)].Should().NotBeNull();
-    }
-
     /// <summary>
     /// The test agent is a simple agent that is used for testing purposes.
     /// </summary>

From 9f78691c409dc54e068d48c256ffd80dead4550c Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 12:40:08 -0800
Subject: [PATCH 071/110] format

---
 dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs     | 2 +-
 .../Runtime.Grpc/Services/Orleans/RegistryGrain.cs         | 7 ++++---
 2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs b/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
index e5fbb4c99025..7e2260d313a2 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/MessageExtensions.cs
@@ -55,7 +55,7 @@ public static CloudEvent ToCloudEvent<T>(this T message, string key, string topi
     /// <summary>
     public static string GetSubject(this CloudEvent cloudEvent)
     {
-        if(cloudEvent.Attributes.TryGetValue("subject", out var value))
+        if (cloudEvent.Attributes.TryGetValue("subject", out var value))
         {
             return value.CeString;
         }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index 3145b8f6b87d..5dce2b5ef649 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -22,10 +22,10 @@ public override Task OnActivateAsync(CancellationToken cancellationToken)
     public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType)
     {
         // get all agent types that are subscribed to the topic
-        if(state.State.TopicToAgentTypesMap.TryGetValue(topic, out var subscribedAgentTypes))
+        if (state.State.TopicToAgentTypesMap.TryGetValue(topic, out var subscribedAgentTypes))
         {
             // get all agent types that are handling the event
-            if(state.State.EventsToAgentTypesMap.TryGetValue(eventType, out var handlingAgents))
+            if (state.State.EventsToAgentTypesMap.TryGetValue(eventType, out var handlingAgents))
             {
                 // return the intersection of the two sets
                 return new(subscribedAgentTypes.Intersect(handlingAgents).ToList());
@@ -34,7 +34,8 @@ public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, stri
             {
                 return new();
             }
-        } else
+        }
+        else
         {
             return new();
         }

From bfaf6f1b3cf4b1d51950feae045612b2eead90e1 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 13:07:33 -0800
Subject: [PATCH 072/110] keep alive ping scenarios always

---
 .../Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs            | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index e91f7ee28752..c22a2b551806 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -28,7 +28,7 @@ public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBu
                     EnableMultipleHttp2Connections = true,
                     KeepAlivePingDelay = TimeSpan.FromSeconds(20),
                     KeepAlivePingTimeout = TimeSpan.FromSeconds(10),
-                    KeepAlivePingPolicy = HttpKeepAlivePingPolicy.WithActiveRequests
+                    KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always
                 };
 
                 var methodConfig = new MethodConfig

From 8109d339c1b8a3261b60c220388c1ec955e9830a Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 14:02:12 -0800
Subject: [PATCH 073/110] package name was wrong

---
 dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index c63c4efc2c8c..79e7c57042cd 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -10,7 +10,7 @@
 using Microsoft.Extensions.Hosting;
 using Microsoft.Extensions.Logging;
 
-namespace Microsoft.AutoGen.Core;
+namespace Microsoft.AutoGen.Core.Grpc;
 
 public sealed class GrpcAgentWorker(
     AgentRpc.AgentRpcClient client,

From e2264965c56af73f4fb319b0a32f66a10011a26c Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 14:12:54 -0800
Subject: [PATCH 074/110] accidentally changed uv.lock

---
 python/uv.lock | 2307 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 2219 insertions(+), 88 deletions(-)

diff --git a/python/uv.lock b/python/uv.lock
index 84bfac995e61..e8a07804e93d 100644
--- a/python/uv.lock
+++ b/python/uv.lock
@@ -1,42 +1,18 @@
 version = 1
 requires-python = ">=3.10, <3.13"
 resolution-markers = [
-    "python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'",
-    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
-    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform == 'darwin'",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
-    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
-    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
-    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
-    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
-    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
-    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
-    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform == 'darwin'",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
-    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
-    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version == '3.11.*' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
-    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version == '3.11.*' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform == 'darwin'",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'darwin'",
-    "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform == 'darwin') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'darwin')",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Darwin' and sys_platform == 'linux'",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform == 'linux'",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform == 'linux'",
-    "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system == 'Darwin' and sys_platform != 'darwin') or (python_full_version < '3.11' and platform_system == 'Darwin' and sys_platform != 'darwin' and sys_platform != 'linux')",
-    "python_full_version < '3.11' and platform_machine == 'aarch64' and platform_system == 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux'",
-    "(python_full_version < '3.11' and platform_machine != 'aarch64' and platform_system != 'Darwin' and sys_platform != 'darwin') or (python_full_version < '3.11' and platform_system != 'Darwin' and platform_system != 'Linux' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version >= '3.12.4' and sys_platform == 'darwin'",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform == 'darwin'",
+    "python_full_version >= '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'",
+    "python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine == 'aarch64' and sys_platform == 'linux'",
+    "(python_full_version >= '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "(python_full_version >= '3.12' and python_full_version < '3.12.4' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and python_full_version < '3.12.4' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version == '3.11.*' and sys_platform == 'darwin'",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'",
+    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')",
+    "python_full_version < '3.11' and sys_platform == 'darwin'",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'",
+    "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')",
 ]
 
 [manifest]
@@ -58,6 +34,29 @@ overrides = [
     { name = "tenacity", specifier = ">=9.0.0" },
 ]
 
+[manifest.dependency-groups]
+dev = [
+    { name = "chainlit" },
+    { name = "cookiecutter" },
+    { name = "grpcio-tools", specifier = "~=1.62.0" },
+    { name = "mypy", specifier = "==1.13.0" },
+    { name = "mypy-protobuf" },
+    { name = "packaging" },
+    { name = "poethepoet" },
+    { name = "polars" },
+    { name = "pyright", specifier = "==1.1.389" },
+    { name = "pytest" },
+    { name = "pytest-asyncio" },
+    { name = "pytest-cov" },
+    { name = "pytest-mock" },
+    { name = "pytest-xdist" },
+    { name = "rich" },
+    { name = "ruff", specifier = "==0.4.8" },
+    { name = "tomli" },
+    { name = "tomli-w" },
+    { name = "typer" },
+]
+
 [[package]]
 name = "accelerate"
 version = "1.3.0"
@@ -76,6 +75,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/73/de/64508cb91af013aaba214752309c0967568a4219d50a4ea30e822af3c976/accelerate-1.3.0-py3-none-any.whl", hash = "sha256:5788d9e6a7a9f80fed665cf09681c4dddd9dc056bea656db4140ffc285ce423e", size = 336647 },
 ]
 
+[[package]]
+name = "accessible-pygments"
+version = "0.0.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pygments" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz", hash = "sha256:40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872", size = 1377899 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl", hash = "sha256:88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7", size = 1395903 },
+]
+
 [[package]]
 name = "agbench"
 version = "0.0.1a1"
@@ -90,6 +101,12 @@ dependencies = [
     { name = "tabulate" },
 ]
 
+[package.dev-dependencies]
+dev = [
+    { name = "types-docker" },
+    { name = "types-tabulate" },
+]
+
 [package.metadata]
 requires-dist = [
     { name = "azure-identity" },
@@ -101,6 +118,12 @@ requires-dist = [
     { name = "tabulate" },
 ]
 
+[package.metadata.requires-dev]
+dev = [
+    { name = "types-docker" },
+    { name = "types-tabulate" },
+]
+
 [[package]]
 name = "aiofiles"
 version = "24.1.0"
@@ -126,7 +149,7 @@ source = { registry = "https://pypi.org/simple" }
 dependencies = [
     { name = "aiohappyeyeballs" },
     { name = "aiosignal" },
-    { name = "async-timeout", marker = "python_full_version < '3.11'" },
+    { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
     { name = "attrs" },
     { name = "frozenlist" },
     { name = "multidict" },
@@ -182,6 +205,19 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/7f/23/cc36d9c398980acaeeb443100f0216f50a7cfe20c67a9fd0a2f1a5a846de/aiohttp-3.11.11-cp312-cp312-win_amd64.whl", hash = "sha256:1e69966ea6ef0c14ee53ef7a3d68b564cc408121ea56c0caa2dc918c1b2f553d", size = 437666 },
 ]
 
+[[package]]
+name = "aiohttp-jinja2"
+version = "1.6"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "jinja2" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e6/39/da5a94dd89b1af7241fb7fc99ae4e73505b5f898b540b6aba6dc7afe600e/aiohttp-jinja2-1.6.tar.gz", hash = "sha256:a3a7ff5264e5bca52e8ae547bbfd0761b72495230d438d05b6c0915be619b0e2", size = 53057 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/eb/90/65238d4246307195411b87a07d03539049819b022c01bcc773826f600138/aiohttp_jinja2-1.6-py3-none-any.whl", hash = "sha256:0df405ee6ad1b58e5a068a105407dc7dcc1704544c559f1938babde954f945c7", size = 11736 },
+]
+
 [[package]]
 name = "aiolimiter"
 version = "1.2.1"
@@ -203,6 +239,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597 },
 ]
 
+[[package]]
+name = "alabaster"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e", size = 24210 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b", size = 13929 },
+]
+
 [[package]]
 name = "alembic"
 version = "1.14.0"
@@ -280,6 +325,19 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 },
 ]
 
+[[package]]
+name = "arrow"
+version = "1.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "python-dateutil" },
+    { name = "types-python-dateutil" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2e/00/0f6e8fcdb23ea632c866620cc872729ff43ed91d284c866b515c6342b173/arrow-1.3.0.tar.gz", hash = "sha256:d4540617648cb5f895730f1ad8c82a65f2dad0166f57b75f3ca54759c4d67a85", size = 131960 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/f8/ed/e97229a566617f2ae958a6b13e7cc0f585470eac730a73e9e82c32a3cdd2/arrow-1.3.0-py3-none-any.whl", hash = "sha256:c728b120ebc00eb84e01882a6f5e7927a53960aa990ce7dd2b10f39005a67f80", size = 66419 },
+]
+
 [[package]]
 name = "asttokens"
 version = "2.4.1"
@@ -296,11 +354,51 @@ wheels = [
 name = "async-timeout"
 version = "4.0.3"
 source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+    "python_full_version < '3.11' and sys_platform == 'darwin'",
+    "python_full_version < '3.11' and platform_machine == 'aarch64' and sys_platform == 'linux'",
+    "(python_full_version < '3.11' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.11' and sys_platform != 'darwin' and sys_platform != 'linux')",
+]
 sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345 }
 wheels = [
     { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 },
 ]
 
+[[package]]
+name = "async-timeout"
+version = "5.0.1"
+source = { registry = "https://pypi.org/simple" }
+resolution-markers = [
+    "python_full_version == '3.11.*' and sys_platform == 'darwin'",
+    "python_full_version == '3.11.*' and platform_machine == 'aarch64' and sys_platform == 'linux'",
+    "(python_full_version == '3.11.*' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version == '3.11.*' and sys_platform != 'darwin' and sys_platform != 'linux')",
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233 },
+]
+
+[[package]]
+name = "asyncer"
+version = "0.0.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "anyio" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/39/29/245ba9fa5769a1e3226c1157aedb372fe9dab28c4e1dcf6911d84d3a5e04/asyncer-0.0.7.tar.gz", hash = "sha256:d5e563fb0f56eb87b97257984703658a4f5bbdb52ff851b3e8ed864cc200b1d2", size = 14437 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/3e/4b/40a1dc52fc26695b1e80a9e67dfb0fe7e6ddc57bbc5b61348e40c0045abb/asyncer-0.0.7-py3-none-any.whl", hash = "sha256:f0d579d4f67c4ead52ede3a45c854f462cae569058a8a6a68a4ebccac1c335d8", size = 8476 },
+]
+
+[[package]]
+name = "asyncio-atexit"
+version = "1.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/22/d3/dd2974be3f67c7ec96e0d6ab454429d0372cb7c7bffa3d0ac67a483cb801/asyncio-atexit-1.0.1.tar.gz", hash = "sha256:1d0c71544b8ee2c484d322844ee72c0875dde6f250c0ed5b6993592ab9f7d436", size = 4373 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/65/10/d6abaefa57a52646651fd0383c056280b0853c0106229ece6bb38cd14463/asyncio_atexit-1.0.1-py3-none-any.whl", hash = "sha256:d93d5f7d5633a534abd521ce2896ed0fbe8de170bb1e65ec871d1c20eac9d376", size = 3752 },
+]
+
 [[package]]
 name = "attrs"
 version = "24.3.0"
@@ -310,6 +408,19 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/89/aa/ab0f7891a01eeb2d2e338ae8fecbe57fcebea1a24dbb64d45801bfab481d/attrs-24.3.0-py3-none-any.whl", hash = "sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308", size = 63397 },
 ]
 
+[[package]]
+name = "autodoc-pydantic"
+version = "2.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pydantic" },
+    { name = "pydantic-settings" },
+    { name = "sphinx" },
+]
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7b/df/87120e2195f08d760bc5cf8a31cfa2381a6887517aa89453b23f1ae3354f/autodoc_pydantic-2.2.0-py3-none-any.whl", hash = "sha256:8c6a36fbf6ed2700ea9c6d21ea76ad541b621fbdf16b5a80ee04673548af4d95", size = 34001 },
+]
+
 [[package]]
 name = "autogen-agentchat"
 version = "0.4.3"
@@ -334,6 +445,54 @@ dependencies = [
     { name = "typing-extensions" },
 ]
 
+[package.dev-dependencies]
+dev = [
+    { name = "aiofiles" },
+    { name = "asyncio-atexit" },
+    { name = "autodoc-pydantic" },
+    { name = "autogen-ext" },
+    { name = "autogen-test-utils" },
+    { name = "azure-identity" },
+    { name = "chess" },
+    { name = "colorama" },
+    { name = "diskcache" },
+    { name = "langchain-openai" },
+    { name = "langgraph" },
+    { name = "llama-index" },
+    { name = "llama-index-embeddings-azure-openai" },
+    { name = "llama-index-llms-azure-openai" },
+    { name = "llama-index-readers-web" },
+    { name = "llama-index-readers-wikipedia" },
+    { name = "llama-index-tools-wikipedia" },
+    { name = "markdownify" },
+    { name = "myst-nb" },
+    { name = "nbqa" },
+    { name = "opentelemetry-sdk" },
+    { name = "pip" },
+    { name = "polars" },
+    { name = "pydata-sphinx-theme" },
+    { name = "pygments" },
+    { name = "python-dotenv" },
+    { name = "redis" },
+    { name = "requests" },
+    { name = "sphinx" },
+    { name = "sphinx-autobuild" },
+    { name = "sphinx-copybutton" },
+    { name = "sphinx-design" },
+    { name = "sphinxcontrib-apidoc" },
+    { name = "sphinxext-rediraffe" },
+    { name = "tavily-python" },
+    { name = "textual" },
+    { name = "textual-dev" },
+    { name = "textual-imageview" },
+    { name = "types-aiofiles" },
+    { name = "types-docker" },
+    { name = "types-pillow" },
+    { name = "types-protobuf" },
+    { name = "types-requests" },
+    { name = "wikipedia" },
+]
+
 [package.metadata]
 requires-dist = [
     { name = "jsonref", specifier = "~=1.1.0" },
@@ -344,6 +503,54 @@ requires-dist = [
     { name = "typing-extensions", specifier = ">=4.0.0" },
 ]
 
+[package.metadata.requires-dev]
+dev = [
+    { name = "aiofiles" },
+    { name = "asyncio-atexit" },
+    { name = "autodoc-pydantic", specifier = "~=2.2" },
+    { name = "autogen-ext", editable = "packages/autogen-ext" },
+    { name = "autogen-test-utils", editable = "packages/autogen-test-utils" },
+    { name = "azure-identity" },
+    { name = "chess" },
+    { name = "colorama" },
+    { name = "diskcache" },
+    { name = "langchain-openai" },
+    { name = "langgraph" },
+    { name = "llama-index" },
+    { name = "llama-index-embeddings-azure-openai" },
+    { name = "llama-index-llms-azure-openai" },
+    { name = "llama-index-readers-web" },
+    { name = "llama-index-readers-wikipedia" },
+    { name = "llama-index-tools-wikipedia" },
+    { name = "markdownify" },
+    { name = "myst-nb", specifier = "==1.1.2" },
+    { name = "nbqa" },
+    { name = "opentelemetry-sdk", specifier = ">=1.27.0" },
+    { name = "pip" },
+    { name = "polars" },
+    { name = "pydata-sphinx-theme", specifier = "==0.15.4" },
+    { name = "pygments" },
+    { name = "python-dotenv" },
+    { name = "redis" },
+    { name = "requests" },
+    { name = "sphinx" },
+    { name = "sphinx-autobuild" },
+    { name = "sphinx-copybutton" },
+    { name = "sphinx-design" },
+    { name = "sphinxcontrib-apidoc" },
+    { name = "sphinxext-rediraffe" },
+    { name = "tavily-python" },
+    { name = "textual" },
+    { name = "textual-dev" },
+    { name = "textual-imageview" },
+    { name = "types-aiofiles" },
+    { name = "types-docker" },
+    { name = "types-pillow" },
+    { name = "types-protobuf" },
+    { name = "types-requests" },
+    { name = "wikipedia" },
+]
+
 [[package]]
 name = "autogen-ext"
 version = "0.4.3"
@@ -440,6 +647,13 @@ web-surfer = [
     { name = "playwright" },
 ]
 
+[package.dev-dependencies]
+dev = [
+    { name = "autogen-test-utils" },
+    { name = "langchain-experimental" },
+    { name = "pandas-stubs" },
+]
+
 [package.metadata]
 requires-dist = [
     { name = "aiofiles", marker = "extra == 'openai'" },
@@ -483,6 +697,13 @@ requires-dist = [
     { name = "tiktoken", marker = "extra == 'openai'", specifier = ">=0.8.0" },
 ]
 
+[package.metadata.requires-dev]
+dev = [
+    { name = "autogen-test-utils", editable = "packages/autogen-test-utils" },
+    { name = "langchain-experimental" },
+    { name = "pandas-stubs", specifier = ">=2.2.3.241126" },
+]
+
 [[package]]
 name = "autogen-magentic-one"
 version = "0.0.1"
@@ -509,6 +730,16 @@ dependencies = [
     { name = "youtube-transcript-api" },
 ]
 
+[package.dev-dependencies]
+dev = [
+    { name = "aiofiles" },
+    { name = "azure-identity" },
+    { name = "openpyxl" },
+    { name = "types-aiofiles" },
+    { name = "types-pillow" },
+    { name = "types-requests" },
+]
+
 [package.metadata]
 requires-dist = [
     { name = "aiofiles" },
@@ -532,6 +763,16 @@ requires-dist = [
     { name = "youtube-transcript-api" },
 ]
 
+[package.metadata.requires-dev]
+dev = [
+    { name = "aiofiles" },
+    { name = "azure-identity" },
+    { name = "openpyxl" },
+    { name = "types-aiofiles" },
+    { name = "types-pillow" },
+    { name = "types-requests" },
+]
+
 [[package]]
 name = "autogen-test-utils"
 version = "0.0.0"
@@ -620,6 +861,19 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/6d/90/d13cf396989052cadd8511c1878b0913bbce28eeef5feb95710a92e03076/autograd-1.7.0-py3-none-any.whl", hash = "sha256:49680300f842f3a8722b060ac0d3ed7aca071d1ad4d3d38c9fdadafdcc73c30b", size = 52522 },
 ]
 
+[[package]]
+name = "autopep8"
+version = "2.3.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pycodestyle" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/50/d8/30873d2b7b57dee9263e53d142da044c4600a46f2d28374b3e38b023df16/autopep8-2.3.2.tar.gz", hash = "sha256:89440a4f969197b69a995e4ce0661b031f455a9f776d2c5ba3dbd83466931758", size = 92210 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/9e/43/53afb8ba17218f19b77c7834128566c5bbb100a0ad9ba2e8e89d089d7079/autopep8-2.3.2-py2.py3-none-any.whl", hash = "sha256:ce8ad498672c845a0c3de2629c15b635ec2b05ef8177a6e7c91c74f3e9b51128", size = 45807 },
+]
+
 [[package]]
 name = "azure-common"
 version = "1.1.28"
@@ -702,6 +956,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/e2/f8/ef0f76f8c424bedd20c685409836ddfb42ac76fd8a0f21c3c3659cf7207d/azure_storage_blob-12.24.0-py3-none-any.whl", hash = "sha256:4f0bb4592ea79a2d986063696514c781c9e62be240f09f6397986e01755bc071", size = 408579 },
 ]
 
+[[package]]
+name = "babel"
+version = "2.16.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/2a/74/f1bc80f23eeba13393b7222b11d95ca3af2c1e28edca18af487137eefed9/babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316", size = 9348104 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ed/20/bc79bc575ba2e2a7f70e8a1155618bb1301eaa5132a8271373a6903f73f8/babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b", size = 9587599 },
+]
+
 [[package]]
 name = "beartype"
 version = "0.18.5"
@@ -723,6 +986,27 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b1/fe/e8c672695b37eecc5cbf43e1d0638d88d66ba3a44c4d321c796f4e59167f/beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed", size = 147925 },
 ]
 
+[[package]]
+name = "bidict"
+version = "0.23.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764 },
+]
+
+[[package]]
+name = "binaryornot"
+version = "0.4.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "chardet" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a7/fe/7ebfec74d49f97fc55cd38240c7a7d08134002b1e14be8c3897c0dd5e49b/binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061", size = 371054 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/24/7e/f7b6f453e6481d1e233540262ccbfcf89adcd43606f44a028d7f5fae5eb2/binaryornot-0.4.4-py2.py3-none-any.whl", hash = "sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4", size = 9006 },
+]
+
 [[package]]
 name = "blinker"
 version = "1.9.0"
@@ -824,6 +1108,39 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 },
 ]
 
+[[package]]
+name = "chainlit"
+version = "2.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiofiles" },
+    { name = "asyncer" },
+    { name = "click" },
+    { name = "dataclasses-json" },
+    { name = "fastapi" },
+    { name = "filetype" },
+    { name = "httpx" },
+    { name = "lazify" },
+    { name = "literalai" },
+    { name = "nest-asyncio" },
+    { name = "packaging" },
+    { name = "pydantic" },
+    { name = "pyjwt" },
+    { name = "python-dotenv" },
+    { name = "python-multipart" },
+    { name = "python-socketio" },
+    { name = "starlette" },
+    { name = "syncer" },
+    { name = "tomli" },
+    { name = "uptrace" },
+    { name = "uvicorn" },
+    { name = "watchfiles" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e0/15/26dc5f957c6344813b2ae8c6f52cc820a7074088509ea947da0cf76ffc5f/chainlit-2.0.1.tar.gz", hash = "sha256:9fb7728aa5704e823c5b5d51f570dcfabafdcc97c23a73e6047f65eb72c938e7", size = 4637433 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ca/99/c63fa2e1d7b949c034b7fc838a0c00de22cd2cec30245e379c9dd15dedfd/chainlit-2.0.1-py3-none-any.whl", hash = "sha256:84982902c6f42a91ac341ea9b6d52e6b1348e53a60ee49b4ffe0e5e5be02f4ba", size = 4703745 },
+]
+
 [[package]]
 name = "chardet"
 version = "5.2.0"
@@ -881,12 +1198,39 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 },
 ]
 
+[[package]]
+name = "chess"
+version = "1.11.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/74/16/53b895bb4fccede8e506de820fa94db03a2dc8bd2ca4bec0aac4a112fb65/chess-1.11.1.tar.gz", hash = "sha256:b7f66a32dc599ab260e2b688e6ac4e868dad840377a54b61357e2dec2a5fed00", size = 156529 }
+
+[[package]]
+name = "chevron"
+version = "0.14.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/15/1f/ca74b65b19798895d63a6e92874162f44233467c9e7c1ed8afd19016ebe9/chevron-0.14.0.tar.gz", hash = "sha256:87613aafdf6d77b6a90ff073165a61ae5086e21ad49057aa0e53681601800ebf", size = 11440 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/52/93/342cc62a70ab727e093ed98e02a725d85b746345f05d2b5e5034649f4ec8/chevron-0.14.0-py3-none-any.whl", hash = "sha256:fbf996a709f8da2e745ef763f482ce2d311aa817d287593a5b990d6d6e4f0443", size = 11595 },
+]
+
+[[package]]
+name = "chromedriver-autoinstaller"
+version = "0.6.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "packaging" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d0/5a/9fc60c65673444d592b8922316c3abcd6177b42208c5a6179f96ccf0e11b/chromedriver-autoinstaller-0.6.4.tar.gz", hash = "sha256:1b4df04b87e6107c730085b98e5fd541db3d1777c32b8bd08e2ca4b1244050af", size = 6944 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a5/b5/36f0b0add145c371b5282e881a687601899f2d27fae5d0595bc02026b67c/chromedriver_autoinstaller-0.6.4-py3-none-any.whl", hash = "sha256:b12ed187ca9fac4d744deb588d221222ed50836384607e5303e6eab98bb9dc64", size = 7634 },
+]
+
 [[package]]
 name = "click"
 version = "8.1.8"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "colorama", marker = "platform_system == 'Windows'" },
+    { name = "colorama", marker = "sys_platform == 'win32'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
 wheels = [
@@ -1006,6 +1350,69 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/52/94/86bfae441707205634d80392e873295652fc313dfd93c233c52c4dc07874/contourpy-1.3.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:44a29502ca9c7b5ba389e620d44f2fbe792b1fb5734e8b931ad307071ec58c53", size = 218221 },
 ]
 
+[[package]]
+name = "cookiecutter"
+version = "2.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "arrow" },
+    { name = "binaryornot" },
+    { name = "click" },
+    { name = "jinja2" },
+    { name = "python-slugify" },
+    { name = "pyyaml" },
+    { name = "requests" },
+    { name = "rich" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/52/17/9f2cd228eb949a91915acd38d3eecdc9d8893dde353b603f0db7e9f6be55/cookiecutter-2.6.0.tar.gz", hash = "sha256:db21f8169ea4f4fdc2408d48ca44859349de2647fbe494a9d6c3edfc0542c21c", size = 158767 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/b6/d9/0137658a353168ffa9d0fc14b812d3834772040858ddd1cb6eeaf09f7a44/cookiecutter-2.6.0-py3-none-any.whl", hash = "sha256:a54a8e37995e4ed963b3e82831072d1ad4b005af736bb17b99c2cbd9d41b6e2d", size = 39177 },
+]
+
+[[package]]
+name = "coverage"
+version = "7.6.10"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/84/ba/ac14d281f80aab516275012e8875991bb06203957aa1e19950139238d658/coverage-7.6.10.tar.gz", hash = "sha256:7fb105327c8f8f0682e29843e2ff96af9dcbe5bab8eeb4b398c6a33a16d80a23", size = 803868 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c5/12/2a2a923edf4ddabdffed7ad6da50d96a5c126dae7b80a33df7310e329a1e/coverage-7.6.10-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5c912978f7fbf47ef99cec50c4401340436d200d41d714c7a4766f377c5b7b78", size = 207982 },
+    { url = "https://files.pythonhosted.org/packages/ca/49/6985dbca9c7be3f3cb62a2e6e492a0c88b65bf40579e16c71ae9c33c6b23/coverage-7.6.10-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a01ec4af7dfeb96ff0078ad9a48810bb0cc8abcb0115180c6013a6b26237626c", size = 208414 },
+    { url = "https://files.pythonhosted.org/packages/35/93/287e8f1d1ed2646f4e0b2605d14616c9a8a2697d0d1b453815eb5c6cebdb/coverage-7.6.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3b204c11e2b2d883946fe1d97f89403aa1811df28ce0447439178cc7463448a", size = 236860 },
+    { url = "https://files.pythonhosted.org/packages/de/e1/cfdb5627a03567a10031acc629b75d45a4ca1616e54f7133ca1fa366050a/coverage-7.6.10-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:32ee6d8491fcfc82652a37109f69dee9a830e9379166cb73c16d8dc5c2915165", size = 234758 },
+    { url = "https://files.pythonhosted.org/packages/6d/85/fc0de2bcda3f97c2ee9fe8568f7d48f7279e91068958e5b2cc19e0e5f600/coverage-7.6.10-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:675cefc4c06e3b4c876b85bfb7c59c5e2218167bbd4da5075cbe3b5790a28988", size = 235920 },
+    { url = "https://files.pythonhosted.org/packages/79/73/ef4ea0105531506a6f4cf4ba571a214b14a884630b567ed65b3d9c1975e1/coverage-7.6.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f4f620668dbc6f5e909a0946a877310fb3d57aea8198bde792aae369ee1c23b5", size = 234986 },
+    { url = "https://files.pythonhosted.org/packages/c6/4d/75afcfe4432e2ad0405c6f27adeb109ff8976c5e636af8604f94f29fa3fc/coverage-7.6.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4eea95ef275de7abaef630c9b2c002ffbc01918b726a39f5a4353916ec72d2f3", size = 233446 },
+    { url = "https://files.pythonhosted.org/packages/86/5b/efee56a89c16171288cafff022e8af44f8f94075c2d8da563c3935212871/coverage-7.6.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e2f0280519e42b0a17550072861e0bc8a80a0870de260f9796157d3fca2733c5", size = 234566 },
+    { url = "https://files.pythonhosted.org/packages/f2/db/67770cceb4a64d3198bf2aa49946f411b85ec6b0a9b489e61c8467a4253b/coverage-7.6.10-cp310-cp310-win32.whl", hash = "sha256:bc67deb76bc3717f22e765ab3e07ee9c7a5e26b9019ca19a3b063d9f4b874244", size = 210675 },
+    { url = "https://files.pythonhosted.org/packages/8d/27/e8bfc43f5345ec2c27bc8a1fa77cdc5ce9dcf954445e11f14bb70b889d14/coverage-7.6.10-cp310-cp310-win_amd64.whl", hash = "sha256:0f460286cb94036455e703c66988851d970fdfd8acc2a1122ab7f4f904e4029e", size = 211518 },
+    { url = "https://files.pythonhosted.org/packages/85/d2/5e175fcf6766cf7501a8541d81778fd2f52f4870100e791f5327fd23270b/coverage-7.6.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ea3c8f04b3e4af80e17bab607c386a830ffc2fb88a5484e1df756478cf70d1d3", size = 208088 },
+    { url = "https://files.pythonhosted.org/packages/4b/6f/06db4dc8fca33c13b673986e20e466fd936235a6ec1f0045c3853ac1b593/coverage-7.6.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:507a20fc863cae1d5720797761b42d2d87a04b3e5aeb682ef3b7332e90598f43", size = 208536 },
+    { url = "https://files.pythonhosted.org/packages/0d/62/c6a0cf80318c1c1af376d52df444da3608eafc913b82c84a4600d8349472/coverage-7.6.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37a84878285b903c0fe21ac8794c6dab58150e9359f1aaebbeddd6412d53132", size = 240474 },
+    { url = "https://files.pythonhosted.org/packages/a3/59/750adafc2e57786d2e8739a46b680d4fb0fbc2d57fbcb161290a9f1ecf23/coverage-7.6.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a534738b47b0de1995f85f582d983d94031dffb48ab86c95bdf88dc62212142f", size = 237880 },
+    { url = "https://files.pythonhosted.org/packages/2c/f8/ef009b3b98e9f7033c19deb40d629354aab1d8b2d7f9cfec284dbedf5096/coverage-7.6.10-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d7a2bf79378d8fb8afaa994f91bfd8215134f8631d27eba3e0e2c13546ce994", size = 239750 },
+    { url = "https://files.pythonhosted.org/packages/a6/e2/6622f3b70f5f5b59f705e680dae6db64421af05a5d1e389afd24dae62e5b/coverage-7.6.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6713ba4b4ebc330f3def51df1d5d38fad60b66720948112f114968feb52d3f99", size = 238642 },
+    { url = "https://files.pythonhosted.org/packages/2d/10/57ac3f191a3c95c67844099514ff44e6e19b2915cd1c22269fb27f9b17b6/coverage-7.6.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ab32947f481f7e8c763fa2c92fd9f44eeb143e7610c4ca9ecd6a36adab4081bd", size = 237266 },
+    { url = "https://files.pythonhosted.org/packages/ee/2d/7016f4ad9d553cabcb7333ed78ff9d27248ec4eba8dd21fa488254dff894/coverage-7.6.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7bbd8c8f1b115b892e34ba66a097b915d3871db7ce0e6b9901f462ff3a975377", size = 238045 },
+    { url = "https://files.pythonhosted.org/packages/a7/fe/45af5c82389a71e0cae4546413266d2195c3744849669b0bab4b5f2c75da/coverage-7.6.10-cp311-cp311-win32.whl", hash = "sha256:299e91b274c5c9cdb64cbdf1b3e4a8fe538a7a86acdd08fae52301b28ba297f8", size = 210647 },
+    { url = "https://files.pythonhosted.org/packages/db/11/3f8e803a43b79bc534c6a506674da9d614e990e37118b4506faf70d46ed6/coverage-7.6.10-cp311-cp311-win_amd64.whl", hash = "sha256:489a01f94aa581dbd961f306e37d75d4ba16104bbfa2b0edb21d29b73be83609", size = 211508 },
+    { url = "https://files.pythonhosted.org/packages/86/77/19d09ea06f92fdf0487499283b1b7af06bc422ea94534c8fe3a4cd023641/coverage-7.6.10-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:27c6e64726b307782fa5cbe531e7647aee385a29b2107cd87ba7c0105a5d3853", size = 208281 },
+    { url = "https://files.pythonhosted.org/packages/b6/67/5479b9f2f99fcfb49c0d5cf61912a5255ef80b6e80a3cddba39c38146cf4/coverage-7.6.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c56e097019e72c373bae32d946ecf9858fda841e48d82df7e81c63ac25554078", size = 208514 },
+    { url = "https://files.pythonhosted.org/packages/15/d1/febf59030ce1c83b7331c3546d7317e5120c5966471727aa7ac157729c4b/coverage-7.6.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7827a5bc7bdb197b9e066cdf650b2887597ad124dd99777332776f7b7c7d0d0", size = 241537 },
+    { url = "https://files.pythonhosted.org/packages/4b/7e/5ac4c90192130e7cf8b63153fe620c8bfd9068f89a6d9b5f26f1550f7a26/coverage-7.6.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:204a8238afe787323a8b47d8be4df89772d5c1e4651b9ffa808552bdf20e1d50", size = 238572 },
+    { url = "https://files.pythonhosted.org/packages/dc/03/0334a79b26ecf59958f2fe9dd1f5ab3e2f88db876f5071933de39af09647/coverage-7.6.10-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67926f51821b8e9deb6426ff3164870976fe414d033ad90ea75e7ed0c2e5022", size = 240639 },
+    { url = "https://files.pythonhosted.org/packages/d7/45/8a707f23c202208d7b286d78ad6233f50dcf929319b664b6cc18a03c1aae/coverage-7.6.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e78b270eadb5702938c3dbe9367f878249b5ef9a2fcc5360ac7bff694310d17b", size = 240072 },
+    { url = "https://files.pythonhosted.org/packages/66/02/603ce0ac2d02bc7b393279ef618940b4a0535b0868ee791140bda9ecfa40/coverage-7.6.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:714f942b9c15c3a7a5fe6876ce30af831c2ad4ce902410b7466b662358c852c0", size = 238386 },
+    { url = "https://files.pythonhosted.org/packages/04/62/4e6887e9be060f5d18f1dd58c2838b2d9646faf353232dec4e2d4b1c8644/coverage-7.6.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:abb02e2f5a3187b2ac4cd46b8ced85a0858230b577ccb2c62c81482ca7d18852", size = 240054 },
+    { url = "https://files.pythonhosted.org/packages/5c/74/83ae4151c170d8bd071924f212add22a0e62a7fe2b149edf016aeecad17c/coverage-7.6.10-cp312-cp312-win32.whl", hash = "sha256:55b201b97286cf61f5e76063f9e2a1d8d2972fc2fcfd2c1272530172fd28c359", size = 210904 },
+    { url = "https://files.pythonhosted.org/packages/c3/54/de0893186a221478f5880283119fc40483bc460b27c4c71d1b8bba3474b9/coverage-7.6.10-cp312-cp312-win_amd64.whl", hash = "sha256:e4ae5ac5e0d1e4edfc9b4b57b4cbecd5bc266a6915c500f358817a8496739247", size = 211692 },
+    { url = "https://files.pythonhosted.org/packages/a1/70/de81bfec9ed38a64fc44a77c7665e20ca507fc3265597c28b0d989e4082e/coverage-7.6.10-pp39.pp310-none-any.whl", hash = "sha256:fd34e7b3405f0cc7ab03d54a334c17a9e802897580d964bd8c2001f4b9fd488f", size = 200223 },
+]
+
+[package.optional-dependencies]
+toml = [
+    { name = "tomli", marker = "python_full_version <= '3.11'" },
+]
+
 [[package]]
 name = "cryptography"
 version = "44.0.0"
@@ -1043,6 +1450,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/cc/9d/37e5da7519de7b0b070a3fedd4230fe76d50d2a21403e0f2153d70ac4163/cryptography-44.0.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c", size = 3128774 },
 ]
 
+[[package]]
+name = "cssselect"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d1/91/d51202cc41fbfca7fa332f43a5adac4b253962588c7cc5a54824b019081c/cssselect-1.2.0.tar.gz", hash = "sha256:666b19839cfaddb9ce9d36bfe4c969132c647b92fc9088c4e23f786b30f1b3dc", size = 41423 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/06/a9/2da08717a6862c48f1d61ef957a7bba171e7eefa6c0aa0ceb96a140c2a6b/cssselect-1.2.0-py2.py3-none-any.whl", hash = "sha256:da1885f0c10b60c03ed5eccbb6b68d6eff248d91976fcde348f395d54c9fd35e", size = 18687 },
+]
+
 [[package]]
 name = "cycler"
 version = "0.12.1"
@@ -1083,6 +1499,19 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/aa/3f/94cff4e36962b843a78a831770b9b44e476a5f9c76c0d53f7cf92053a1b4/dapr_ext_fastapi-1.14.0-py3-none-any.whl", hash = "sha256:88df67d6af33fd5adcf97d8799fa43373774b13cb9a1091ac4dd47e18a009ca0", size = 10458 },
 ]
 
+[[package]]
+name = "dataclasses-json"
+version = "0.6.7"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "marshmallow" },
+    { name = "typing-inspect" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/64/a4/f71d9cf3a5ac257c993b5ca3f93df5f7fb395c725e7f1e6479d2514173c3/dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0", size = 32227 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c3/be/d0d44e092656fe7a06b55e6103cbce807cdbdee17884a5367c68c9860853/dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a", size = 28686 },
+]
+
 [[package]]
 name = "debugpy"
 version = "1.8.11"
@@ -1160,6 +1589,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d1/ae/afb1487556e2dc827a17097aac8158a25b433a345386f0e249f6d2694ccb/devtools-0.12.2-py3-none-any.whl", hash = "sha256:c366e3de1df4cdd635f1ad8cbcd3af01a384d7abda71900e68d43b04eb6aaca7", size = 19411 },
 ]
 
+[[package]]
+name = "dirtyjson"
+version = "1.0.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/db/04/d24f6e645ad82ba0ef092fa17d9ef7a21953781663648a01c9371d9e8e98/dirtyjson-1.0.8.tar.gz", hash = "sha256:90ca4a18f3ff30ce849d100dcf4a003953c79d3a2348ef056f1d9c22231a25fd", size = 30782 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/68/69/1bcf70f81de1b4a9f21b3a62ec0c83bdff991c88d6cc2267d02408457e88/dirtyjson-1.0.8-py3-none-any.whl", hash = "sha256:125e27248435a58acace26d5c2c4c11a1c0de0a9c5124c5a94ba78e517d74f53", size = 25197 },
+]
+
 [[package]]
 name = "diskcache"
 version = "5.6.3"
@@ -1201,6 +1639,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d5/7c/e9fcff7623954d86bdc17782036cbf715ecab1bec4847c008557affe1ca8/docstring_parser-0.16-py3-none-any.whl", hash = "sha256:bf0a1387354d3691d102edef7ec124f219ef639982d096e26e3b60aeffa90637", size = 36533 },
 ]
 
+[[package]]
+name = "docutils"
+version = "0.21.2"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f", size = 2204444 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2", size = 587408 },
+]
+
 [[package]]
 name = "environs"
 version = "11.2.1"
@@ -1241,6 +1688,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
 ]
 
+[[package]]
+name = "execnet"
+version = "2.1.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/bb/ff/b4c0dc78fbe20c3e59c0c7334de0c27eb4001a2b2017999af398bf730817/execnet-2.1.1.tar.gz", hash = "sha256:5189b52c6121c24feae288166ab41b32549c7e2348652736540b9e6e7d4e72e3", size = 166524 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/43/09/2aea36ff60d16dd8879bdb2f5b3ee0ba8d08cbbdcdfe870e695ce3784385/execnet-2.1.1-py3-none-any.whl", hash = "sha256:26dee51f1b80cebd6d0ca8e74dd8745419761d3bef34163928cbebbdc4749fdc", size = 40612 },
+]
+
 [[package]]
 name = "executing"
 version = "2.1.0"
@@ -1273,6 +1729,29 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/90/2b/0817a2b257fe88725c25589d89aec060581aabf668707a8d03b2e9e0cb2a/fastjsonschema-2.21.1-py3-none-any.whl", hash = "sha256:c9e5b7e908310918cf494a434eeb31384dd84a98b57a30bcb1f535015b554667", size = 23924 },
 ]
 
+[[package]]
+name = "feedfinder2"
+version = "0.0.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "beautifulsoup4" },
+    { name = "requests" },
+    { name = "six" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/35/82/1251fefec3bb4b03fd966c7e7f7a41c9fc2bb00d823a34c13f847fd61406/feedfinder2-0.0.4.tar.gz", hash = "sha256:3701ee01a6c85f8b865a049c30ba0b4608858c803fe8e30d1d289fdbe89d0efe", size = 3297 }
+
+[[package]]
+name = "feedparser"
+version = "6.0.11"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "sgmllib3k" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ff/aa/7af346ebeb42a76bf108027fe7f3328bb4e57a3a96e53e21fd9ef9dd6dd0/feedparser-6.0.11.tar.gz", hash = "sha256:c9d0407b64c6f2a065d0ebb292c2b35c01050cc0dc33757461aaabdc4c4184d5", size = 286197 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7c/d4/8c31aad9cc18f451c49f7f9cfb5799dadffc88177f7917bc90a66459b1d7/feedparser-6.0.11-py3-none-any.whl", hash = "sha256:0be7ee7b395572b19ebeb1d6aafb0028dee11169f1c934e0ed67d54992f4ad45", size = 81343 },
+]
+
 [[package]]
 name = "ffmpeg-python"
 version = "0.2.0"
@@ -1294,6 +1773,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b9/f8/feced7779d755758a52d1f6635d990b8d98dc0a29fa568bbe0625f18fdf3/filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0", size = 16163 },
 ]
 
+[[package]]
+name = "filetype"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970 },
+]
+
 [[package]]
 name = "flask"
 version = "3.1.0"
@@ -1897,6 +2385,43 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/90/40/972271de05f9315c0d69f9f7ebbcadd83bc85322f538637d11bb8c67803d/grpcio_status-1.62.3-py3-none-any.whl", hash = "sha256:f9049b762ba8de6b1086789d8315846e094edac2c50beaf462338b301a8fd4b8", size = 14448 },
 ]
 
+[[package]]
+name = "grpcio-tools"
+version = "1.62.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "grpcio" },
+    { name = "protobuf" },
+    { name = "setuptools" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/54/fa/b69bd8040eafc09b88bb0ec0fea59e8aacd1a801e688af087cead213b0d0/grpcio-tools-1.62.3.tar.gz", hash = "sha256:7c7136015c3d62c3eef493efabaf9e3380e3e66d24ee8e94c01cb71377f57833", size = 4538520 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ff/eb/eb0a3aa9480c3689d31fd2ad536df6a828e97a60f667c8a93d05bdf07150/grpcio_tools-1.62.3-cp310-cp310-macosx_12_0_universal2.whl", hash = "sha256:2f968b049c2849540751ec2100ab05e8086c24bead769ca734fdab58698408c1", size = 5117556 },
+    { url = "https://files.pythonhosted.org/packages/f3/fb/8be3dda485f7fab906bfa02db321c3ecef953a87cdb5f6572ca08b187bcb/grpcio_tools-1.62.3-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:0a8c0c4724ae9c2181b7dbc9b186df46e4f62cb18dc184e46d06c0ebeccf569e", size = 2719330 },
+    { url = "https://files.pythonhosted.org/packages/63/de/6978f8d10066e240141cd63d1fbfc92818d96bb53427074f47a8eda921e1/grpcio_tools-1.62.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5782883a27d3fae8c425b29a9d3dcf5f47d992848a1b76970da3b5a28d424b26", size = 3070818 },
+    { url = "https://files.pythonhosted.org/packages/74/34/bb8f816893fc73fd6d830e895e8638d65d13642bb7a434f9175c5ca7da11/grpcio_tools-1.62.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3d812daffd0c2d2794756bd45a353f89e55dc8f91eb2fc840c51b9f6be62667", size = 2804993 },
+    { url = "https://files.pythonhosted.org/packages/78/60/b2198d7db83293cdb9760fc083f077c73e4c182da06433b3b157a1567d06/grpcio_tools-1.62.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b47d0dda1bdb0a0ba7a9a6de88e5a1ed61f07fad613964879954961e36d49193", size = 3684915 },
+    { url = "https://files.pythonhosted.org/packages/61/20/56dbdc4ecb14d42a03cd164ff45e6e84572bbe61ee59c50c39f4d556a8d5/grpcio_tools-1.62.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ca246dffeca0498be9b4e1ee169b62e64694b0f92e6d0be2573e65522f39eea9", size = 3297482 },
+    { url = "https://files.pythonhosted.org/packages/4a/dc/e417a313c905744ce8cedf1e1edd81c41dc45ff400ae1c45080e18f26712/grpcio_tools-1.62.3-cp310-cp310-win32.whl", hash = "sha256:6a56d344b0bab30bf342a67e33d386b0b3c4e65868ffe93c341c51e1a8853ca5", size = 909793 },
+    { url = "https://files.pythonhosted.org/packages/d9/69/75e7ebfd8d755d3e7be5c6d1aa6d13220f5bba3a98965e4b50c329046777/grpcio_tools-1.62.3-cp310-cp310-win_amd64.whl", hash = "sha256:710fecf6a171dcbfa263a0a3e7070e0df65ba73158d4c539cec50978f11dad5d", size = 1052459 },
+    { url = "https://files.pythonhosted.org/packages/23/52/2dfe0a46b63f5ebcd976570aa5fc62f793d5a8b169e211c6a5aede72b7ae/grpcio_tools-1.62.3-cp311-cp311-macosx_10_10_universal2.whl", hash = "sha256:703f46e0012af83a36082b5f30341113474ed0d91e36640da713355cd0ea5d23", size = 5147623 },
+    { url = "https://files.pythonhosted.org/packages/f0/2e/29fdc6c034e058482e054b4a3c2432f84ff2e2765c1342d4f0aa8a5c5b9a/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:7cc83023acd8bc72cf74c2edbe85b52098501d5b74d8377bfa06f3e929803492", size = 2719538 },
+    { url = "https://files.pythonhosted.org/packages/f9/60/abe5deba32d9ec2c76cdf1a2f34e404c50787074a2fee6169568986273f1/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ff7d58a45b75df67d25f8f144936a3e44aabd91afec833ee06826bd02b7fbe7", size = 3070964 },
+    { url = "https://files.pythonhosted.org/packages/bc/ad/e2b066684c75f8d9a48508cde080a3a36618064b9cadac16d019ca511444/grpcio_tools-1.62.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f2483ea232bd72d98a6dc6d7aefd97e5bc80b15cd909b9e356d6f3e326b6e43", size = 2805003 },
+    { url = "https://files.pythonhosted.org/packages/9c/3f/59bf7af786eae3f9d24ee05ce75318b87f541d0950190ecb5ffb776a1a58/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:962c84b4da0f3b14b3cdb10bc3837ebc5f136b67d919aea8d7bb3fd3df39528a", size = 3685154 },
+    { url = "https://files.pythonhosted.org/packages/f1/79/4dd62478b91e27084c67b35a2316ce8a967bd8b6cb8d6ed6c86c3a0df7cb/grpcio_tools-1.62.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8ad0473af5544f89fc5a1ece8676dd03bdf160fb3230f967e05d0f4bf89620e3", size = 3297942 },
+    { url = "https://files.pythonhosted.org/packages/b8/cb/86449ecc58bea056b52c0b891f26977afc8c4464d88c738f9648da941a75/grpcio_tools-1.62.3-cp311-cp311-win32.whl", hash = "sha256:db3bc9fa39afc5e4e2767da4459df82b095ef0cab2f257707be06c44a1c2c3e5", size = 910231 },
+    { url = "https://files.pythonhosted.org/packages/45/a4/9736215e3945c30ab6843280b0c6e1bff502910156ea2414cd77fbf1738c/grpcio_tools-1.62.3-cp311-cp311-win_amd64.whl", hash = "sha256:e0898d412a434e768a0c7e365acabe13ff1558b767e400936e26b5b6ed1ee51f", size = 1052496 },
+    { url = "https://files.pythonhosted.org/packages/2a/a5/d6887eba415ce318ae5005e8dfac3fa74892400b54b6d37b79e8b4f14f5e/grpcio_tools-1.62.3-cp312-cp312-macosx_10_10_universal2.whl", hash = "sha256:d102b9b21c4e1e40af9a2ab3c6d41afba6bd29c0aa50ca013bf85c99cdc44ac5", size = 5147690 },
+    { url = "https://files.pythonhosted.org/packages/8a/7c/3cde447a045e83ceb4b570af8afe67ffc86896a2fe7f59594dc8e5d0a645/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:0a52cc9444df978438b8d2332c0ca99000521895229934a59f94f37ed896b133", size = 2720538 },
+    { url = "https://files.pythonhosted.org/packages/88/07/f83f2750d44ac4f06c07c37395b9c1383ef5c994745f73c6bfaf767f0944/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:141d028bf5762d4a97f981c501da873589df3f7e02f4c1260e1921e565b376fa", size = 3071571 },
+    { url = "https://files.pythonhosted.org/packages/37/74/40175897deb61e54aca716bc2e8919155b48f33aafec8043dda9592d8768/grpcio_tools-1.62.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47a5c093ab256dec5714a7a345f8cc89315cb57c298b276fa244f37a0ba507f0", size = 2806207 },
+    { url = "https://files.pythonhosted.org/packages/ec/ee/d8de915105a217cbcb9084d684abdc032030dcd887277f2ef167372287fe/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f6831fdec2b853c9daa3358535c55eed3694325889aa714070528cf8f92d7d6d", size = 3685815 },
+    { url = "https://files.pythonhosted.org/packages/fd/d9/4360a6c12be3d7521b0b8c39e5d3801d622fbb81cc2721dbd3eee31e28c8/grpcio_tools-1.62.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e02d7c1a02e3814c94ba0cfe43d93e872c758bd8fd5c2797f894d0c49b4a1dfc", size = 3298378 },
+    { url = "https://files.pythonhosted.org/packages/29/3b/7cdf4a9e5a3e0a35a528b48b111355cd14da601413a4f887aa99b6da468f/grpcio_tools-1.62.3-cp312-cp312-win32.whl", hash = "sha256:b881fd9505a84457e9f7e99362eeedd86497b659030cf57c6f0070df6d9c2b9b", size = 910416 },
+    { url = "https://files.pythonhosted.org/packages/6c/66/dd3ec249e44c1cc15e902e783747819ed41ead1336fcba72bf841f72c6e9/grpcio_tools-1.62.3-cp312-cp312-win_amd64.whl", hash = "sha256:11c625eebefd1fd40a228fc8bae385e448c7e32a6ae134e43cf13bbc23f902b7", size = 1052856 },
+]
+
 [[package]]
 name = "h11"
 version = "0.14.0"
@@ -1906,6 +2431,12 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
 ]
 
+[[package]]
+name = "html2text"
+version = "2024.2.26"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/1a/43/e1d53588561e533212117750ee79ad0ba02a41f52a08c1df3396bd466c05/html2text-2024.2.26.tar.gz", hash = "sha256:05f8e367d15aaabc96415376776cdd11afd5127a77fce6e36afc60c563ca2c32", size = 56527 }
+
 [[package]]
 name = "httpcore"
 version = "1.0.7"
@@ -1947,10 +2478,19 @@ wheels = [
 ]
 
 [[package]]
-name = "huggingface-hub"
-version = "0.27.1"
+name = "httpx-sse"
+version = "0.4.0"
 source = { registry = "https://pypi.org/simple" }
-dependencies = [
+sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
+]
+
+[[package]]
+name = "huggingface-hub"
+version = "0.27.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
     { name = "filelock" },
     { name = "fsspec" },
     { name = "packaging" },
@@ -2000,6 +2540,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
 ]
 
+[[package]]
+name = "imagesize"
+version = "1.4.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a7/84/62473fb57d61e31fef6e36d64a179c8781605429fd927b5dd608c997be31/imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a", size = 1280026 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ff/62/85c4c919272577931d407be5ba5d71c20f0b616d31a0befe0ae45bb79abd/imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b", size = 8769 },
+]
+
 [[package]]
 name = "importlib-metadata"
 version = "8.4.0"
@@ -2026,7 +2575,7 @@ name = "ipykernel"
 version = "6.29.5"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "appnope", marker = "platform_system == 'Darwin'" },
+    { name = "appnope", marker = "sys_platform == 'darwin'" },
     { name = "comm" },
     { name = "debugpy" },
     { name = "ipython" },
@@ -2097,6 +2646,12 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278 },
 ]
 
+[[package]]
+name = "jieba3k"
+version = "0.35.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a9/cb/2c8332bcdc14d33b0bedd18ae0a4981a069c3513e445120da3c3f23a8aaa/jieba3k-0.35.1.zip", hash = "sha256:980a4f2636b778d312518066be90c7697d410dd5a472385f5afced71a2db1c10", size = 7423646 }
+
 [[package]]
 name = "jinja2"
 version = "3.1.5"
@@ -2261,6 +2816,25 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d1/0f/8910b19ac0670a0f80ce1008e5e751c4a57e14d2c4c13a482aa6079fa9d6/jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf", size = 18459 },
 ]
 
+[[package]]
+name = "jupyter-cache"
+version = "1.0.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "attrs" },
+    { name = "click" },
+    { name = "importlib-metadata" },
+    { name = "nbclient" },
+    { name = "nbformat" },
+    { name = "pyyaml" },
+    { name = "sqlalchemy" },
+    { name = "tabulate" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bb/f7/3627358075f183956e8c4974603232b03afd4ddc7baf72c2bc9fff522291/jupyter_cache-1.0.1.tar.gz", hash = "sha256:16e808eb19e3fb67a223db906e131ea6e01f03aa27f49a7214ce6a5fec186fb9", size = 32048 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/64/6b/67b87da9d36bff9df7d0efbd1a325fa372a43be7158effaf43ed7b22341d/jupyter_cache-1.0.1-py3-none-any.whl", hash = "sha256:9c3cafd825ba7da8b5830485343091143dff903e4d8c69db9349b728b140abf6", size = 33907 },
+]
+
 [[package]]
 name = "jupyter-client"
 version = "8.6.3"
@@ -2371,6 +2945,51 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/34/b9/a3d4bfdaefbc9098ef18bff2cf403c6060f70894c5022983464f9c3db367/lancedb-0.17.0-cp39-abi3-win_amd64.whl", hash = "sha256:9d7e82f83f430d906c285d3303729258b21b1cc8da634c9f7017e354bcb7318a", size = 27511050 },
 ]
 
+[[package]]
+name = "langchain"
+version = "0.3.14"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+    { name = "langchain-core" },
+    { name = "langchain-text-splitters" },
+    { name = "langsmith" },
+    { name = "numpy" },
+    { name = "pydantic" },
+    { name = "pyyaml" },
+    { name = "requests" },
+    { name = "sqlalchemy" },
+    { name = "tenacity" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/18/35/2adb0693acc149e462bc0e7856ecd58096c285f66a78bc44fc2b8ae91ce0/langchain-0.3.14.tar.gz", hash = "sha256:4a5ae817b5832fa0e1fcadc5353fbf74bebd2f8e550294d4dc039f651ddcd3d1", size = 420409 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d0/a8/0a8f868615b7a30636b1d15b718e3ea9875bf0dccced03583477c2372495/langchain-0.3.14-py3-none-any.whl", hash = "sha256:5df9031702f7fe6c956e84256b4639a46d5d03a75be1ca4c1bc9479b358061a2", size = 1009213 },
+]
+
+[[package]]
+name = "langchain-community"
+version = "0.3.14"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "dataclasses-json" },
+    { name = "httpx-sse" },
+    { name = "langchain" },
+    { name = "langchain-core" },
+    { name = "langsmith" },
+    { name = "numpy" },
+    { name = "pydantic-settings" },
+    { name = "pyyaml" },
+    { name = "requests" },
+    { name = "sqlalchemy" },
+    { name = "tenacity" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/a32cddaa9e8c618e69cfbfdb11cb8718bd9a531ae8426f6a2125a7a5d31f/langchain_community-0.3.14.tar.gz", hash = "sha256:d8ba0fe2dbb5795bff707684b712baa5ee379227194610af415ccdfdefda0479", size = 1720031 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7b/df/3a226f47aad50605a4ff77a30e876d7520f2060aa624532872e44ea048d8/langchain_community-0.3.14-py3-none-any.whl", hash = "sha256:cc02a0abad0551edef3e565dff643386a5b2ee45b933b6d883d4a935b9649f3c", size = 2502417 },
+]
+
 [[package]]
 name = "langchain-core"
 version = "0.3.29"
@@ -2389,6 +3008,85 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/95/4f/fe1de63f6fc1ac7af3ba4ae12d420af1a19f7893b5fcb72856b9fc67f650/langchain_core-0.3.29-py3-none-any.whl", hash = "sha256:817db1474871611a81105594a3e4d11704949661008e455a10e38ca9ff601a1a", size = 411593 },
 ]
 
+[[package]]
+name = "langchain-experimental"
+version = "0.3.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "langchain-community" },
+    { name = "langchain-core" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/27/56/a8acbb08a03383c28875b3b151e4cefea5612266917fbd6fc3c14c21e172/langchain_experimental-0.3.4.tar.gz", hash = "sha256:937c4259ee4a639c618d19acf0e2c5c2898ef127050346edc5655259aa281a21", size = 140532 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/b2/27/fe8caa4884611286b1f7d6c5cfd76e1fef188faaa946db4fde6daa1cd2cd/langchain_experimental-0.3.4-py3-none-any.whl", hash = "sha256:2e587306aea36b60fa5e5fc05dc7281bee9f60a806f0bf9d30916e0ee096af80", size = 209154 },
+]
+
+[[package]]
+name = "langchain-openai"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "langchain-core" },
+    { name = "openai" },
+    { name = "tiktoken" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/16/0a/0711117a4e8273d5edd4899399a8597d848b2d7b3c9ba3be97038b4fbc1a/langchain_openai-0.3.0.tar.gz", hash = "sha256:88d623eeb2aaa1fff65c2b419a4a1cfd37d3a1d504e598b87cf0bc822a3b70d0", size = 48067 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/4a/9c/b38e308ac668f6db067b424a2a78e5b865753c144a119456f008a09230db/langchain_openai-0.3.0-py3-none-any.whl", hash = "sha256:49c921a22d272b04749a61e78bffa83aecdb8840b24b69f2909e115a357a9a5b", size = 54218 },
+]
+
+[[package]]
+name = "langchain-text-splitters"
+version = "0.3.5"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "langchain-core" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/10/35/a6f8d6b1bb0e6e8c00b49bce4d1a115f8b68368b1899f65bb34dbbb44160/langchain_text_splitters-0.3.5.tar.gz", hash = "sha256:11cb7ca3694e5bdd342bc16d3875b7f7381651d4a53cbb91d34f22412ae16443", size = 26318 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/4b/83/f8081c3bea416bd9d9f0c26af795c74f42c24f9ad3c4fbf361b7d69de134/langchain_text_splitters-0.3.5-py3-none-any.whl", hash = "sha256:8c9b059827438c5fa8f327b4df857e307828a5ec815163c9b5c9569a3e82c8ee", size = 31620 },
+]
+
+[[package]]
+name = "langgraph"
+version = "0.2.62"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "langchain-core" },
+    { name = "langgraph-checkpoint" },
+    { name = "langgraph-sdk" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/54/bb/23859e3c219944bc9f1f3093629970631b3a6dc0aeaf607d7d205b2b551e/langgraph-0.2.62.tar.gz", hash = "sha256:0aac9fd55ffe669bc1312203e0f9ea2733c65cc276f196e7ff0d443cf4efbb89", size = 119343 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/30/38/571f8bc14d4ced8e9d86aca657ffd9a6d076e32e2a62d487eab15f2ceca7/langgraph-0.2.62-py3-none-any.whl", hash = "sha256:51ae9e02a52485a837642eebe7ae43269af7d7305d62f8f69ac11589b2fbba26", size = 138170 },
+]
+
+[[package]]
+name = "langgraph-checkpoint"
+version = "2.0.10"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "langchain-core" },
+    { name = "msgpack" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/26/96/378e06c60d8c8cf44e1d6a2b669e9d5d87236bdee6bf7cfc9125ef5b5d0e/langgraph_checkpoint-2.0.10.tar.gz", hash = "sha256:2dcc04e09091d588bb6209e49d83ff5406d7231c2590d6ff18fb29ab8b140129", size = 33431 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/4d/ef/c320b52035e29081f2693377602289a00545016b4adcc963d5e202ac0c92/langgraph_checkpoint-2.0.10-py3-none-any.whl", hash = "sha256:0d592cfda2df93844c6ea44d142170a8f7e5ba5320274e0e5e60e27f2749392c", size = 37476 },
+]
+
+[[package]]
+name = "langgraph-sdk"
+version = "0.1.51"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "httpx" },
+    { name = "orjson" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/32/d1/95ae599428e8e7d90229e402adf3056072f2ebd0c45c7f7154a5243ff35a/langgraph_sdk-0.1.51.tar.gz", hash = "sha256:dea1363e72562cb1e82a2d156be8d5b1a69ff3fe8815eee0e1e7a2f423242ec1", size = 41591 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/86/e9/d5d2ea883ddb3e16d4c18213457b3f3d04380089d410db71faae52a3c34a/langgraph_sdk-0.1.51-py3-none-any.whl", hash = "sha256:ce2b58466d1700d06149782ed113157a8694a6d7932c801f316cd13fab315fe4", size = 44652 },
+]
+
 [[package]]
 name = "langsmith"
 version = "0.2.10"
@@ -2405,6 +3103,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/12/91/e72d13f6b57a0ea9d884ab1d3388f544d7fe3354dbe1d4dd67678693a9fd/langsmith-0.2.10-py3-none-any.whl", hash = "sha256:b02f2f174189ff72e54c88b1aa63343defd6f0f676c396a690c63a4b6495dcc2", size = 326432 },
 ]
 
+[[package]]
+name = "lazify"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/24/2c/b55c4a27a56dd9a00bb2812c404b57f8b7aec0cdbff9fdc61acdd73359bc/Lazify-0.4.0.tar.gz", hash = "sha256:7102bfe63e56de2ab62b3bc661a7190c4056771a8624f04a8b785275c3dd1f9b", size = 2968 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/03/a5/866b44697cee47d1cae429ed370281d937ad4439f71af82a6baaa139d26a/Lazify-0.4.0-py2.py3-none-any.whl", hash = "sha256:c2c17a7a33e9406897e3f66fde4cd3f84716218d580330e5af10cfe5a0cd195a", size = 3107 },
+]
+
 [[package]]
 name = "lazy-object-proxy"
 version = "1.10.0"
@@ -2435,6 +3142,327 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/31/8b/94dc8d58704ab87b39faed6f2fc0090b9d90e2e2aa2bbec35c79f3d2a054/lazy_object_proxy-1.10.0-pp310.pp311.pp312.pp38.pp39-none-any.whl", hash = "sha256:80fa48bd89c8f2f456fc0765c11c23bf5af827febacd2f523ca5bc1893fcc09d", size = 16405 },
 ]
 
+[[package]]
+name = "linkify-it-py"
+version = "2.0.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "uc-micro-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2a/ae/bb56c6828e4797ba5a4821eec7c43b8bf40f69cda4d4f5f8c8a2810ec96a/linkify-it-py-2.0.3.tar.gz", hash = "sha256:68cda27e162e9215c17d786649d1da0021a451bdc436ef9e0fa0ba5234b9b048", size = 27946 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/04/1e/b832de447dee8b582cac175871d2f6c3d5077cc56d5575cadba1fd1cccfa/linkify_it_py-2.0.3-py3-none-any.whl", hash = "sha256:6bcbc417b0ac14323382aef5c5192c0075bf8a9d6b41820a2b66371eac6b6d79", size = 19820 },
+]
+
+[[package]]
+name = "literalai"
+version = "0.0.623"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "chevron" },
+    { name = "httpx" },
+    { name = "packaging" },
+    { name = "pydantic" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/41/af/07d943e62a1297a7b44777297c0dca8f4bfcd6ae18b9df7d3cd9c1970e29/literalai-0.0.623.tar.gz", hash = "sha256:d65c04dde6b1e99d585e4112a607e5fd574d282b70f600c55a671018340dfb0f", size = 57081 }
+
+[[package]]
+name = "llama-cloud"
+version = "0.1.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "certifi" },
+    { name = "httpx" },
+    { name = "pydantic" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a0/e8/6dcc69cd624f3267e41e2077f33f98c27727a9842a5d8244ce6cf0671859/llama_cloud-0.1.8.tar.gz", hash = "sha256:7199bab2240a9cc330740003fa77648f43f6e533da411a8250a4a70584f91153", size = 90827 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/99/0f/af106de1780cf526c96de1ba279edcb55a0376a4484a7dea206f9f038cc4/llama_cloud-0.1.8-py3-none-any.whl", hash = "sha256:1a0c4cf212a04f2375f1d0791ca4e5f196e0fb0567c4ec96cd9dbcad773de60a", size = 247083 },
+]
+
+[[package]]
+name = "llama-index"
+version = "0.12.11"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-agent-openai" },
+    { name = "llama-index-cli" },
+    { name = "llama-index-core" },
+    { name = "llama-index-embeddings-openai" },
+    { name = "llama-index-indices-managed-llama-cloud" },
+    { name = "llama-index-llms-openai" },
+    { name = "llama-index-multi-modal-llms-openai" },
+    { name = "llama-index-program-openai" },
+    { name = "llama-index-question-gen-openai" },
+    { name = "llama-index-readers-file" },
+    { name = "llama-index-readers-llama-parse" },
+    { name = "nltk" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/43/34/7eb11a6b6fa603fa0a072c1ffaa08d337d805d09feca5235bd42664d9ec4/llama_index-0.12.11.tar.gz", hash = "sha256:b1116946a2414aec104a6c417b847da5b4f077a0966c50ebd2fc445cd713adce", size = 7781 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d5/72/ab8bae2072c0e7786cbe7348d5b45bfb12972dd3a1fdb5cb96c615b779f6/llama_index-0.12.11-py3-none-any.whl", hash = "sha256:007361c35e1981a1656cef287b7bcdf22aa88e7d41b8e3a8ee261bb5a10519a9", size = 6876 },
+]
+
+[[package]]
+name = "llama-index-agent-openai"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "llama-index-llms-openai" },
+    { name = "openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0b/09/bb3c4d5496f2d79499ca6d323f379e2051473b56a917ed46cf4d0d2aeb05/llama_index_agent_openai-0.4.2.tar.gz", hash = "sha256:0f8aeb091fc834b2667a46ad2417fc8601bf1c08ccfd1a3d15ede90a30eb1a29", size = 10612 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/4d/37/21bdd9adce0e358203a81f245521e829d72547e14ecd6c298ec0327218a1/llama_index_agent_openai-0.4.2-py3-none-any.whl", hash = "sha256:e100b8a743b11fef373b5be31be590b929950a4d7fd9d158b5f014dd8fd7976e", size = 13205 },
+]
+
+[[package]]
+name = "llama-index-cli"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "llama-index-embeddings-openai" },
+    { name = "llama-index-llms-openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/0a/52/81e1448d4dcff5beb1453f397f34f9ac769b7fcdb6b7c8fbd4c20b73e836/llama_index_cli-0.4.0.tar.gz", hash = "sha256:d6ab201359962a8a34368aeda3a49bbbe67e9e009c59bd925c4fb2be4ace3906", size = 24710 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/70/29/2b659e5930ea44253bf99e2afc395daaa2a3edaa579d99e63ea53df03313/llama_index_cli-0.4.0-py3-none-any.whl", hash = "sha256:60d12f89e6b85e80a0cc3a8b531f05a911b5eebaebc37314411476d1ba685904", size = 27785 },
+]
+
+[[package]]
+name = "llama-index-core"
+version = "0.12.11"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "dataclasses-json" },
+    { name = "deprecated" },
+    { name = "dirtyjson" },
+    { name = "filetype" },
+    { name = "fsspec" },
+    { name = "httpx" },
+    { name = "nest-asyncio" },
+    { name = "networkx" },
+    { name = "nltk" },
+    { name = "numpy" },
+    { name = "pillow" },
+    { name = "pydantic" },
+    { name = "pyyaml" },
+    { name = "requests" },
+    { name = "sqlalchemy", extra = ["asyncio"] },
+    { name = "tenacity" },
+    { name = "tiktoken" },
+    { name = "tqdm" },
+    { name = "typing-extensions" },
+    { name = "typing-inspect" },
+    { name = "wrapt" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/8d/a7/1ee40a8bcc5e7ff1dc523f2a26e217b3d7a306d4180b0654e9b4ab519c9c/llama_index_core-0.12.11.tar.gz", hash = "sha256:9a41ca91167ea5eec9ebaac7f5e958b7feddbd8af3bfbf7c393a5edfb994d566", size = 1332167 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d4/fb/3aadbfb0a43a734857802d6c372e70470921aaef3023b5e8f39dbdc6fd94/llama_index_core-0.12.11-py3-none-any.whl", hash = "sha256:3b1e019c899e9e011dfa01c96b7e3f666e0c161035fbca6cb787b4c61e0c94db", size = 1584262 },
+]
+
+[[package]]
+name = "llama-index-embeddings-azure-openai"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "llama-index-embeddings-openai" },
+    { name = "llama-index-llms-azure-openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/48/db/a35c34ff7863315ac133b4ff0386913cbe9986988e7f1c076e1745dbe015/llama_index_embeddings_azure_openai-0.3.0.tar.gz", hash = "sha256:80b0cf977d8b967a08536d65b8e2d0c6c966eeaf1b8fff084e97f3081fd70c34", size = 3111 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/b5/78/eb22765325d03008dae55f98c77053231b9344d2bef6304f3d93121f3468/llama_index_embeddings_azure_openai-0.3.0-py3-none-any.whl", hash = "sha256:2ca61d6b75468d1230cfc1151a878d892b237130b8af09b4434f8c0466d44dfe", size = 3425 },
+]
+
+[[package]]
+name = "llama-index-embeddings-openai"
+version = "0.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/02/a2604ef3a167131fdd701888f45f16c8efa6d523d02efe8c4e640238f4ea/llama_index_embeddings_openai-0.3.1.tar.gz", hash = "sha256:1368aad3ce24cbaed23d5ad251343cef1eb7b4a06d6563d6606d59cb347fef20", size = 5492 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/bb/45/ca55b91c4ac1b6251d4099fa44121a6c012129822906cadcc27b8cfb33a4/llama_index_embeddings_openai-0.3.1-py3-none-any.whl", hash = "sha256:f15a3d13da9b6b21b8bd51d337197879a453d1605e625a1c6d45e741756c0290", size = 6177 },
+]
+
+[[package]]
+name = "llama-index-indices-managed-llama-cloud"
+version = "0.6.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-cloud" },
+    { name = "llama-index-core" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ce/58/29afa6086e2080ae27da79949e319f77f08cb7d1b2bd26e56a676dab1338/llama_index_indices_managed_llama_cloud-0.6.3.tar.gz", hash = "sha256:f09e4182cbc2a2bd75ae85cebb1681075247f0d91b931b094cac4315386ce87a", size = 10483 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/43/c6/ebb53a15e63c8da3633a595f53fc965509e8c6707da6a8b1bfa9b7923236/llama_index_indices_managed_llama_cloud-0.6.3-py3-none-any.whl", hash = "sha256:7f125602f624a2d321b6a4130cd98df35eb8c15818a159390755b2c13068f4ce", size = 11077 },
+]
+
+[[package]]
+name = "llama-index-llms-azure-openai"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "azure-identity" },
+    { name = "httpx" },
+    { name = "llama-index-core" },
+    { name = "llama-index-llms-openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/81/d7/21264774d0e0819d869ac2f6527fd6b405340647feb4fef7b6b59c520858/llama_index_llms_azure_openai-0.3.0.tar.gz", hash = "sha256:0feea9319d832c8b5e8e0f397c905e45df54c529b6a778825adcd0d254bd7d63", size = 5557 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/90/49/a90c17bddddb411e0bc2d05bcf393fb03474279fb6fbe20c98db68473d98/llama_index_llms_azure_openai-0.3.0-py3-none-any.whl", hash = "sha256:24091aedf7ba24a7b217d17c4358e62b5d6b43a4d3ca44750d442b02a440d26e", size = 6306 },
+]
+
+[[package]]
+name = "llama-index-llms-openai"
+version = "0.3.13"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/12/0d/bc11eb89f8c912747d3a41186b8b9a2fc2c15cc52af7866689621e22ab4d/llama_index_llms_openai-0.3.13.tar.gz", hash = "sha256:51dda240dae7671c37e84bb50fe77fe6bb58a9b2a7e33dccd84473c9998afcea", size = 14302 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0a/22/b0dad3dd2b9054d020208cbc86e9fd730c04fe3551a9af2e640593eff6ef/llama_index_llms_openai-0.3.13-py3-none-any.whl", hash = "sha256:caea1d6cb5bdd34518fcefe28b784698c92120ed133e6cd4591f777cd15180b0", size = 14542 },
+]
+
+[[package]]
+name = "llama-index-multi-modal-llms-openai"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "llama-index-llms-openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/eb/32/6f13d3cb79d71504072041d2e83fa67804c7945d2249f7ccadbcbbe15fdc/llama_index_multi_modal_llms_openai-0.4.2.tar.gz", hash = "sha256:3437a08cec85cebbc212aa73da5c9b8b054b4dc628338568435a7df88489476f", size = 5078 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/05/18/14772cebd9674772bc605632c92d4675e86d87a3263c35a90865d6c4918b/llama_index_multi_modal_llms_openai-0.4.2-py3-none-any.whl", hash = "sha256:093f60f59fc423abab110810f8f129b96b0212b9737d74480f0e3e1b715e975b", size = 5855 },
+]
+
+[[package]]
+name = "llama-index-program-openai"
+version = "0.3.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-agent-openai" },
+    { name = "llama-index-core" },
+    { name = "llama-index-llms-openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/7a/b8/24f1103106bfeed04f0e33b587863345c2d7fad001828bb02844a5427fbc/llama_index_program_openai-0.3.1.tar.gz", hash = "sha256:6039a6cdbff62c6388c07e82a157fe2edd3bbef0c5adf292ad8546bf4ec75b82", size = 4818 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/00/59/3f31171c30a08c8ba21155d5241ba174630e57cf43b03d97fd77bf565b51/llama_index_program_openai-0.3.1-py3-none-any.whl", hash = "sha256:93646937395dc5318fd095153d2f91bd632b25215d013d14a87c088887d205f9", size = 5318 },
+]
+
+[[package]]
+name = "llama-index-question-gen-openai"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "llama-index-llms-openai" },
+    { name = "llama-index-program-openai" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4e/47/c57392e2fb00c0f596f912e7977e3c639ac3314f2aed5d4ac733baa367f1/llama_index_question_gen_openai-0.3.0.tar.gz", hash = "sha256:efd3b468232808e9d3474670aaeab00e41b90f75f52d0c9bfbf11207e0963d62", size = 2608 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7c/2c/765b0dfc2c988bbea267e236c836d7a96c60a20df76d842e43e17401f800/llama_index_question_gen_openai-0.3.0-py3-none-any.whl", hash = "sha256:9b60ec114273a63b50349948666e5744a8f58acb645824e07c979041e8fec598", size = 2899 },
+]
+
+[[package]]
+name = "llama-index-readers-file"
+version = "0.4.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "beautifulsoup4" },
+    { name = "llama-index-core" },
+    { name = "pandas" },
+    { name = "pypdf" },
+    { name = "striprtf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/bc/35/62edc3eed9d69d9b5b5faae4c0c82ff05e608b07b0c547a988c23f19a79c/llama_index_readers_file-0.4.3.tar.gz", hash = "sha256:07514bebed7ce431c1b3ef9279d09aa3d1bba8e342d661860a033355b98fb33a", size = 22046 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a5/06/f41f795000c623d4cdaf95729a045a2be819c31f39951d5e88f4bccf37db/llama_index_readers_file-0.4.3-py3-none-any.whl", hash = "sha256:c669da967ea534e3af3660f9fd730c71c725288f5c57906bcce338414ebeee5c", size = 38914 },
+]
+
+[[package]]
+name = "llama-index-readers-llama-parse"
+version = "0.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "llama-parse" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/35/30/4611821286f82ba7b5842295607baa876262db86f88b87d83595eed172bf/llama_index_readers_llama_parse-0.4.0.tar.gz", hash = "sha256:e99ec56f4f8546d7fda1a7c1ae26162fb9acb7ebcac343b5abdb4234b4644e0f", size = 2472 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/68/4f/e30d4257fe9e4224f5612b77fe99aaceddae411b2e74ca30534491de3e6f/llama_index_readers_llama_parse-0.4.0-py3-none-any.whl", hash = "sha256:574e48386f28d2c86c3f961ca4a4906910312f3400dd0c53014465bfbc6b32bf", size = 2472 },
+]
+
+[[package]]
+name = "llama-index-readers-web"
+version = "0.3.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "beautifulsoup4" },
+    { name = "chromedriver-autoinstaller" },
+    { name = "html2text" },
+    { name = "llama-index-core" },
+    { name = "newspaper3k" },
+    { name = "playwright" },
+    { name = "requests" },
+    { name = "selenium" },
+    { name = "spider-client" },
+    { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/89/a5/14e4277c871194092e014fd893f8f17a7c84f447a254696d7985ab9e603c/llama_index_readers_web-0.3.3.tar.gz", hash = "sha256:740373b17456cc46a9b39810253a3c1adfc8814d40f88798bea42115a10626ce", size = 53969 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/98/40/6e290cac34ac217b47347c7b0268114aef1f0c836998647d0c9f0fabc8f0/llama_index_readers_web-0.3.3-py3-none-any.whl", hash = "sha256:ab166bb14a56f5b10b637d6633c861d86bcaa72e7e123c4e31d304e6b1d88efe", size = 76616 },
+]
+
+[[package]]
+name = "llama-index-readers-wikipedia"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ae/f1/1bd33ebbd003f1e19e9a77a85d0e77c0dd0c904de50cc9212cc718648813/llama_index_readers_wikipedia-0.3.0.tar.gz", hash = "sha256:77972387cd5410c981bd427699613de63e76889f99816512fc3fce3b2eca440a", size = 2445 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7b/8a/c85a69d9899fd6b7176bcbf6d19579feb1110e340a48b486f3682bc1bf60/llama_index_readers_wikipedia-0.3.0-py3-none-any.whl", hash = "sha256:1723441901a3a19f323872e3c5a968bbfc98cdc5f35e901c99e79f0e8cb7fa57", size = 2702 },
+]
+
+[[package]]
+name = "llama-index-tools-wikipedia"
+version = "0.3.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "llama-index-core" },
+    { name = "wikipedia" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/86/fc/0ebe0913694a3582c0ae2c96cafb48689a9d012766e5b8a32d59932009de/llama_index_tools_wikipedia-0.3.0.tar.gz", hash = "sha256:8e3fc5ae8a479aacc6640c6c30a66f9848762bf8ebbbc4ceab41e8a4762a664c", size = 2487 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/60/89/0d7aa9a41ed0a0768790da770ef057416b81a92ecc35dc9f9d70a86abbb1/llama_index_tools_wikipedia-0.3.0-py3-none-any.whl", hash = "sha256:aa76c39237056b3ed727a23aadc65f34c5b500449ee9ec2efaced055f3ff9938", size = 2712 },
+]
+
+[[package]]
+name = "llama-parse"
+version = "0.5.19"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "click" },
+    { name = "llama-index-core" },
+    { name = "pydantic" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/3b/02/63839a55f6f207110400c4f394152fd0290e9f8e450226b02a87cfdbd835/llama_parse-0.5.19.tar.gz", hash = "sha256:db69da70e199a2664705eb983a70fa92b7cee19dd6cff175af7692a0b8a4dd53", size = 16100 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/38/b7/3ff106e8199992bb62e72f195c8f6f2f2fe4a185f5f92746f0ed9db5c5d2/llama_parse-0.5.19-py3-none-any.whl", hash = "sha256:715cc895d183531b4299359d4f4004089b2e522f5f137f316084e7aa04035b62", size = 15421 },
+]
+
 [[package]]
 name = "llvmlite"
 version = "0.43.0"
@@ -2551,6 +3579,9 @@ requires-dist = [
     { name = "autogen-ext", extras = ["openai", "magentic-one"], editable = "packages/autogen-ext" },
 ]
 
+[package.metadata.requires-dev]
+dev = []
+
 [[package]]
 name = "mako"
 version = "1.3.8"
@@ -2587,6 +3618,14 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
 ]
 
+[package.optional-dependencies]
+linkify = [
+    { name = "linkify-it-py" },
+]
+plugins = [
+    { name = "mdit-py-plugins" },
+]
+
 [[package]]
 name = "markdownify"
 version = "0.14.1"
@@ -2729,6 +3768,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 },
 ]
 
+[[package]]
+name = "mdit-py-plugins"
+version = "0.4.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "markdown-it-py" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/19/03/a2ecab526543b152300717cf232bb4bb8605b6edb946c845016fa9c9c9fd/mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5", size = 43542 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a7/f7/7782a043553ee469c1ff49cfa1cdace2d6bf99a1f333cf38676b3ddf30da/mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636", size = 55316 },
+]
+
 [[package]]
 name = "mdurl"
 version = "0.1.2"
@@ -2800,6 +3851,47 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 },
 ]
 
+[[package]]
+name = "msgpack"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/cb/d0/7555686ae7ff5731205df1012ede15dd9d927f6227ea151e901c7406af4f/msgpack-1.1.0.tar.gz", hash = "sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e", size = 167260 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/4b/f9/a892a6038c861fa849b11a2bb0502c07bc698ab6ea53359e5771397d883b/msgpack-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ad442d527a7e358a469faf43fda45aaf4ac3249c8310a82f0ccff9164e5dccd", size = 150428 },
+    { url = "https://files.pythonhosted.org/packages/df/7a/d174cc6a3b6bb85556e6a046d3193294a92f9a8e583cdbd46dc8a1d7e7f4/msgpack-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:74bed8f63f8f14d75eec75cf3d04ad581da6b914001b474a5d3cd3372c8cc27d", size = 84131 },
+    { url = "https://files.pythonhosted.org/packages/08/52/bf4fbf72f897a23a56b822997a72c16de07d8d56d7bf273242f884055682/msgpack-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:914571a2a5b4e7606997e169f64ce53a8b1e06f2cf2c3a7273aa106236d43dd5", size = 81215 },
+    { url = "https://files.pythonhosted.org/packages/02/95/dc0044b439b518236aaf012da4677c1b8183ce388411ad1b1e63c32d8979/msgpack-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c921af52214dcbb75e6bdf6a661b23c3e6417f00c603dd2070bccb5c3ef499f5", size = 371229 },
+    { url = "https://files.pythonhosted.org/packages/ff/75/09081792db60470bef19d9c2be89f024d366b1e1973c197bb59e6aabc647/msgpack-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8ce0b22b890be5d252de90d0e0d119f363012027cf256185fc3d474c44b1b9e", size = 378034 },
+    { url = "https://files.pythonhosted.org/packages/32/d3/c152e0c55fead87dd948d4b29879b0f14feeeec92ef1fd2ec21b107c3f49/msgpack-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:73322a6cc57fcee3c0c57c4463d828e9428275fb85a27aa2aa1a92fdc42afd7b", size = 363070 },
+    { url = "https://files.pythonhosted.org/packages/d9/2c/82e73506dd55f9e43ac8aa007c9dd088c6f0de2aa19e8f7330e6a65879fc/msgpack-1.1.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e1f3c3d21f7cf67bcf2da8e494d30a75e4cf60041d98b3f79875afb5b96f3a3f", size = 359863 },
+    { url = "https://files.pythonhosted.org/packages/cb/a0/3d093b248837094220e1edc9ec4337de3443b1cfeeb6e0896af8ccc4cc7a/msgpack-1.1.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:64fc9068d701233effd61b19efb1485587560b66fe57b3e50d29c5d78e7fef68", size = 368166 },
+    { url = "https://files.pythonhosted.org/packages/e4/13/7646f14f06838b406cf5a6ddbb7e8dc78b4996d891ab3b93c33d1ccc8678/msgpack-1.1.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:42f754515e0f683f9c79210a5d1cad631ec3d06cea5172214d2176a42e67e19b", size = 370105 },
+    { url = "https://files.pythonhosted.org/packages/67/fa/dbbd2443e4578e165192dabbc6a22c0812cda2649261b1264ff515f19f15/msgpack-1.1.0-cp310-cp310-win32.whl", hash = "sha256:3df7e6b05571b3814361e8464f9304c42d2196808e0119f55d0d3e62cd5ea044", size = 68513 },
+    { url = "https://files.pythonhosted.org/packages/24/ce/c2c8fbf0ded750cb63cbcbb61bc1f2dfd69e16dca30a8af8ba80ec182dcd/msgpack-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:685ec345eefc757a7c8af44a3032734a739f8c45d1b0ac45efc5d8977aa4720f", size = 74687 },
+    { url = "https://files.pythonhosted.org/packages/b7/5e/a4c7154ba65d93be91f2f1e55f90e76c5f91ccadc7efc4341e6f04c8647f/msgpack-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d364a55082fb2a7416f6c63ae383fbd903adb5a6cf78c5b96cc6316dc1cedc7", size = 150803 },
+    { url = "https://files.pythonhosted.org/packages/60/c2/687684164698f1d51c41778c838d854965dd284a4b9d3a44beba9265c931/msgpack-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:79ec007767b9b56860e0372085f8504db5d06bd6a327a335449508bbee9648fa", size = 84343 },
+    { url = "https://files.pythonhosted.org/packages/42/ae/d3adea9bb4a1342763556078b5765e666f8fdf242e00f3f6657380920972/msgpack-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6ad622bf7756d5a497d5b6836e7fc3752e2dd6f4c648e24b1803f6048596f701", size = 81408 },
+    { url = "https://files.pythonhosted.org/packages/dc/17/6313325a6ff40ce9c3207293aee3ba50104aed6c2c1559d20d09e5c1ff54/msgpack-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e59bca908d9ca0de3dc8684f21ebf9a690fe47b6be93236eb40b99af28b6ea6", size = 396096 },
+    { url = "https://files.pythonhosted.org/packages/a8/a1/ad7b84b91ab5a324e707f4c9761633e357820b011a01e34ce658c1dda7cc/msgpack-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1da8f11a3dd397f0a32c76165cf0c4eb95b31013a94f6ecc0b280c05c91b59", size = 403671 },
+    { url = "https://files.pythonhosted.org/packages/bb/0b/fd5b7c0b308bbf1831df0ca04ec76fe2f5bf6319833646b0a4bd5e9dc76d/msgpack-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:452aff037287acb1d70a804ffd022b21fa2bb7c46bee884dbc864cc9024128a0", size = 387414 },
+    { url = "https://files.pythonhosted.org/packages/f0/03/ff8233b7c6e9929a1f5da3c7860eccd847e2523ca2de0d8ef4878d354cfa/msgpack-1.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8da4bf6d54ceed70e8861f833f83ce0814a2b72102e890cbdfe4b34764cdd66e", size = 383759 },
+    { url = "https://files.pythonhosted.org/packages/1f/1b/eb82e1fed5a16dddd9bc75f0854b6e2fe86c0259c4353666d7fab37d39f4/msgpack-1.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:41c991beebf175faf352fb940bf2af9ad1fb77fd25f38d9142053914947cdbf6", size = 394405 },
+    { url = "https://files.pythonhosted.org/packages/90/2e/962c6004e373d54ecf33d695fb1402f99b51832631e37c49273cc564ffc5/msgpack-1.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a52a1f3a5af7ba1c9ace055b659189f6c669cf3657095b50f9602af3a3ba0fe5", size = 396041 },
+    { url = "https://files.pythonhosted.org/packages/f8/20/6e03342f629474414860c48aeffcc2f7f50ddaf351d95f20c3f1c67399a8/msgpack-1.1.0-cp311-cp311-win32.whl", hash = "sha256:58638690ebd0a06427c5fe1a227bb6b8b9fdc2bd07701bec13c2335c82131a88", size = 68538 },
+    { url = "https://files.pythonhosted.org/packages/aa/c4/5a582fc9a87991a3e6f6800e9bb2f3c82972912235eb9539954f3e9997c7/msgpack-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788", size = 74871 },
+    { url = "https://files.pythonhosted.org/packages/e1/d6/716b7ca1dbde63290d2973d22bbef1b5032ca634c3ff4384a958ec3f093a/msgpack-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d", size = 152421 },
+    { url = "https://files.pythonhosted.org/packages/70/da/5312b067f6773429cec2f8f08b021c06af416bba340c912c2ec778539ed6/msgpack-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5dbad74103df937e1325cc4bfeaf57713be0b4f15e1c2da43ccdd836393e2ea2", size = 85277 },
+    { url = "https://files.pythonhosted.org/packages/28/51/da7f3ae4462e8bb98af0d5bdf2707f1b8c65a0d4f496e46b6afb06cbc286/msgpack-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:58dfc47f8b102da61e8949708b3eafc3504509a5728f8b4ddef84bd9e16ad420", size = 82222 },
+    { url = "https://files.pythonhosted.org/packages/33/af/dc95c4b2a49cff17ce47611ca9ba218198806cad7796c0b01d1e332c86bb/msgpack-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4676e5be1b472909b2ee6356ff425ebedf5142427842aa06b4dfd5117d1ca8a2", size = 392971 },
+    { url = "https://files.pythonhosted.org/packages/f1/54/65af8de681fa8255402c80eda2a501ba467921d5a7a028c9c22a2c2eedb5/msgpack-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17fb65dd0bec285907f68b15734a993ad3fc94332b5bb21b0435846228de1f39", size = 401403 },
+    { url = "https://files.pythonhosted.org/packages/97/8c/e333690777bd33919ab7024269dc3c41c76ef5137b211d776fbb404bfead/msgpack-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a51abd48c6d8ac89e0cfd4fe177c61481aca2d5e7ba42044fd218cfd8ea9899f", size = 385356 },
+    { url = "https://files.pythonhosted.org/packages/57/52/406795ba478dc1c890559dd4e89280fa86506608a28ccf3a72fbf45df9f5/msgpack-1.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2137773500afa5494a61b1208619e3871f75f27b03bcfca7b3a7023284140247", size = 383028 },
+    { url = "https://files.pythonhosted.org/packages/e7/69/053b6549bf90a3acadcd8232eae03e2fefc87f066a5b9fbb37e2e608859f/msgpack-1.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:398b713459fea610861c8a7b62a6fec1882759f308ae0795b5413ff6a160cf3c", size = 391100 },
+    { url = "https://files.pythonhosted.org/packages/23/f0/d4101d4da054f04274995ddc4086c2715d9b93111eb9ed49686c0f7ccc8a/msgpack-1.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:06f5fd2f6bb2a7914922d935d3b8bb4a7fff3a9a91cfce6d06c13bc42bec975b", size = 394254 },
+    { url = "https://files.pythonhosted.org/packages/1c/12/cf07458f35d0d775ff3a2dc5559fa2e1fcd06c46f1ef510e594ebefdca01/msgpack-1.1.0-cp312-cp312-win32.whl", hash = "sha256:ad33e8400e4ec17ba782f7b9cf868977d867ed784a1f5f2ab46e7ba53b6e1e1b", size = 69085 },
+    { url = "https://files.pythonhosted.org/packages/73/80/2708a4641f7d553a63bc934a3eb7214806b5b39d200133ca7f7afb0a53e8/msgpack-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:115a7af8ee9e8cddc10f87636767857e7e3717b7a2e97379dc2054712693e90f", size = 75347 },
+]
+
 [[package]]
 name = "multidict"
 version = "6.1.0"
@@ -2857,6 +3949,35 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 },
 ]
 
+[[package]]
+name = "mypy"
+version = "1.13.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "mypy-extensions" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/e8/21/7e9e523537991d145ab8a0a2fd98548d67646dc2aaaf6091c31ad883e7c1/mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e", size = 3152532 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/5e/8c/206de95a27722b5b5a8c85ba3100467bd86299d92a4f71c6b9aa448bfa2f/mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a", size = 11020731 },
+    { url = "https://files.pythonhosted.org/packages/ab/bb/b31695a29eea76b1569fd28b4ab141a1adc9842edde080d1e8e1776862c7/mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80", size = 10184276 },
+    { url = "https://files.pythonhosted.org/packages/a5/2d/4a23849729bb27934a0e079c9c1aad912167d875c7b070382a408d459651/mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7", size = 12587706 },
+    { url = "https://files.pythonhosted.org/packages/5c/c3/d318e38ada50255e22e23353a469c791379825240e71b0ad03e76ca07ae6/mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f", size = 13105586 },
+    { url = "https://files.pythonhosted.org/packages/4a/25/3918bc64952370c3dbdbd8c82c363804678127815febd2925b7273d9482c/mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372", size = 9632318 },
+    { url = "https://files.pythonhosted.org/packages/d0/19/de0822609e5b93d02579075248c7aa6ceaddcea92f00bf4ea8e4c22e3598/mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d", size = 10939027 },
+    { url = "https://files.pythonhosted.org/packages/c8/71/6950fcc6ca84179137e4cbf7cf41e6b68b4a339a1f5d3e954f8c34e02d66/mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d", size = 10108699 },
+    { url = "https://files.pythonhosted.org/packages/26/50/29d3e7dd166e74dc13d46050b23f7d6d7533acf48f5217663a3719db024e/mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b", size = 12506263 },
+    { url = "https://files.pythonhosted.org/packages/3f/1d/676e76f07f7d5ddcd4227af3938a9c9640f293b7d8a44dd4ff41d4db25c1/mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73", size = 12984688 },
+    { url = "https://files.pythonhosted.org/packages/9c/03/5a85a30ae5407b1d28fab51bd3e2103e52ad0918d1e68f02a7778669a307/mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca", size = 9626811 },
+    { url = "https://files.pythonhosted.org/packages/fb/31/c526a7bd2e5c710ae47717c7a5f53f616db6d9097caf48ad650581e81748/mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5", size = 11077900 },
+    { url = "https://files.pythonhosted.org/packages/83/67/b7419c6b503679d10bd26fc67529bc6a1f7a5f220bbb9f292dc10d33352f/mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e", size = 10074818 },
+    { url = "https://files.pythonhosted.org/packages/ba/07/37d67048786ae84e6612575e173d713c9a05d0ae495dde1e68d972207d98/mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2", size = 12589275 },
+    { url = "https://files.pythonhosted.org/packages/1f/17/b1018c6bb3e9f1ce3956722b3bf91bff86c1cefccca71cec05eae49d6d41/mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0", size = 13037783 },
+    { url = "https://files.pythonhosted.org/packages/cb/32/cd540755579e54a88099aee0287086d996f5a24281a673f78a0e14dba150/mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2", size = 9726197 },
+    { url = "https://files.pythonhosted.org/packages/3b/86/72ce7f57431d87a7ff17d442f521146a6585019eb8f4f31b7c02801f78ad/mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a", size = 2647043 },
+]
+
 [[package]]
 name = "mypy-extensions"
 version = "1.0.0"
@@ -2866,6 +3987,57 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2a/e2/5d3f6ada4297caebe1a2add3b126fe800c96f56dbe5d1988a2cbe0b267aa/mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d", size = 4695 },
 ]
 
+[[package]]
+name = "mypy-protobuf"
+version = "3.6.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "protobuf" },
+    { name = "types-protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4d/6f/282d64d66bf48ce60e38a6560753f784e0f88ab245ac2fb5e93f701a36cd/mypy-protobuf-3.6.0.tar.gz", hash = "sha256:02f242eb3409f66889f2b1a3aa58356ec4d909cdd0f93115622e9e70366eca3c", size = 24445 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e8/73/d6b999782ae22f16971cc05378b3b33f6a89ede3b9619e8366aa23484bca/mypy_protobuf-3.6.0-py3-none-any.whl", hash = "sha256:56176e4d569070e7350ea620262478b49b7efceba4103d468448f1d21492fd6c", size = 16434 },
+]
+
+[[package]]
+name = "myst-nb"
+version = "1.1.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "importlib-metadata" },
+    { name = "ipykernel" },
+    { name = "ipython" },
+    { name = "jupyter-cache" },
+    { name = "myst-parser" },
+    { name = "nbclient" },
+    { name = "nbformat" },
+    { name = "pyyaml" },
+    { name = "sphinx" },
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/04/e3/01c093f6a46be2edc0fd370cbf6d227495ea19452939b2810b36657c63d4/myst_nb-1.1.2.tar.gz", hash = "sha256:961b4005657029ca89892a4c75edbf0856c54ceaf6172368b46bf7676c1f7700", size = 78036 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/04/45/cf78b2f09c46b36f486b75c34a8b48580e53b543bd9a467b3c7eb9054b70/myst_nb-1.1.2-py3-none-any.whl", hash = "sha256:9b7034e5d62640cb6daf03f9ca16ef45d0462fced27944c77aa3f98c7cdcd566", size = 80281 },
+]
+
+[[package]]
+name = "myst-parser"
+version = "4.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "docutils" },
+    { name = "jinja2" },
+    { name = "markdown-it-py" },
+    { name = "mdit-py-plugins" },
+    { name = "pyyaml" },
+    { name = "sphinx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/85/55/6d1741a1780e5e65038b74bce6689da15f620261c490c3511eb4c12bac4b/myst_parser-4.0.0.tar.gz", hash = "sha256:851c9dfb44e36e56d15d05e72f02b80da21a9e0d07cba96baf5e2d476bb91531", size = 93858 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ca/b4/b036f8fdb667587bb37df29dc6644681dd78b7a2a6321a34684b79412b28/myst_parser-4.0.0-py3-none-any.whl", hash = "sha256:b9317997552424448c6096c2558872fdb6f81d3ecb3a40ce84a7518798f3f28d", size = 84563 },
+]
+
 [[package]]
 name = "nbclient"
 version = "0.10.2"
@@ -2896,6 +4068,21 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/a9/82/0340caa499416c78e5d8f5f05947ae4bc3cba53c9f038ab6e9ed964e22f1/nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b", size = 78454 },
 ]
 
+[[package]]
+name = "nbqa"
+version = "1.9.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "autopep8" },
+    { name = "ipython" },
+    { name = "tokenize-rt" },
+    { name = "tomli" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/aa/76/62d2609924cf34445148cd6b5de694cf64c179cc416cac93182579620e57/nbqa-1.9.1.tar.gz", hash = "sha256:a1f4bcf587c597302fed295951001fc4e1be4ce0e77e1ab1b25ac2fbe3db0cdd", size = 38348 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/28/88/4789719fbbe166d12d345b3ac66b96105f10001b16e00a9765ba29261a21/nbqa-1.9.1-py3-none-any.whl", hash = "sha256:95552d2f6c2c038136252a805aa78d85018aef922586270c3a074332737282e5", size = 35259 },
+]
+
 [[package]]
 name = "nest-asyncio"
 version = "1.6.0"
@@ -2914,6 +4101,30 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263 },
 ]
 
+[[package]]
+name = "newspaper3k"
+version = "0.2.8"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "beautifulsoup4" },
+    { name = "cssselect" },
+    { name = "feedfinder2" },
+    { name = "feedparser" },
+    { name = "jieba3k" },
+    { name = "lxml" },
+    { name = "nltk" },
+    { name = "pillow" },
+    { name = "python-dateutil" },
+    { name = "pyyaml" },
+    { name = "requests" },
+    { name = "tinysegmenter" },
+    { name = "tldextract" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ce/fb/8f8525be0cafa48926e85b0c06a7cb3e2a892d340b8036f8c8b1b572df1c/newspaper3k-0.2.8.tar.gz", hash = "sha256:9f1bd3e1fb48f400c715abf875cc7b0a67b7ddcd87f50c9aeeb8fcbbbd9004fb", size = 205685 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d7/b9/51afecb35bb61b188a4b44868001de348a0e8134b4dfa00ffc191567c4b9/newspaper3k-0.2.8-py3-none-any.whl", hash = "sha256:44a864222633d3081113d1030615991c3dbba87239f6bbf59d91240f71a22e3e", size = 211132 },
+]
+
 [[package]]
 name = "nltk"
 version = "3.9.1"
@@ -2929,6 +4140,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/4d/66/7d9e26593edda06e8cb531874633f7c2372279c3b0f46235539fe546df8b/nltk-3.9.1-py3-none-any.whl", hash = "sha256:4fa26829c5b00715afe3061398a8989dc643b92ce7dd93fb4585a70930d168a1", size = 1505442 },
 ]
 
+[[package]]
+name = "nodeenv"
+version = "1.9.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314 },
+]
+
 [[package]]
 name = "numba"
 version = "0.60.0"
@@ -3029,7 +4249,7 @@ name = "nvidia-cudnn-cu12"
 version = "9.1.0.70"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-cublas-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/9f/fd/713452cd72343f682b1c7b9321e23829f00b842ceaedcda96e742ea0b0b3/nvidia_cudnn_cu12-9.1.0.70-py3-none-manylinux2014_x86_64.whl", hash = "sha256:165764f44ef8c61fcdfdfdbe769d687e06374059fbb388b6c89ecb0e28793a6f", size = 664752741 },
@@ -3040,7 +4260,7 @@ name = "nvidia-cufft-cu12"
 version = "11.2.1.3"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/7a/8a/0e728f749baca3fbeffad762738276e5df60851958be7783af121a7221e7/nvidia_cufft_cu12-11.2.1.3-py3-none-manylinux2014_aarch64.whl", hash = "sha256:5dad8008fc7f92f5ddfa2101430917ce2ffacd86824914c82e28990ad7f00399", size = 211422548 },
@@ -3061,9 +4281,9 @@ name = "nvidia-cusolver-cu12"
 version = "11.6.1.9"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-cublas-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
-    { name = "nvidia-cusparse-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
-    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "nvidia-cublas-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "nvidia-cusparse-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/46/6b/a5c33cf16af09166845345275c34ad2190944bcc6026797a39f8e0a282e0/nvidia_cusolver_cu12-11.6.1.9-py3-none-manylinux2014_aarch64.whl", hash = "sha256:d338f155f174f90724bbde3758b7ac375a70ce8e706d70b018dd3375545fc84e", size = 127634111 },
@@ -3075,7 +4295,7 @@ name = "nvidia-cusparse-cu12"
 version = "12.3.1.170"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "nvidia-nvjitlink-cu12", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/96/a9/c0d2f83a53d40a4a41be14cea6a0bf9e668ffcf8b004bd65633f433050c0/nvidia_cusparse_cu12-12.3.1.170-py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d32f62896231ebe0480efd8a7f702e143c98cfaa0e8a76df3386c1ba2b54df3", size = 207381987 },
@@ -3300,6 +4520,93 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/fb/1f/737dcdbc9fea2fa96c1b392ae47275165a7c641663fbb08a8d252968eed2/opentelemetry_api-1.27.0-py3-none-any.whl", hash = "sha256:953d5871815e7c30c81b56d910c707588000fff7a3ca1c73e6531911d53065e7", size = 63970 },
 ]
 
+[[package]]
+name = "opentelemetry-exporter-otlp"
+version = "1.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "opentelemetry-exporter-otlp-proto-grpc" },
+    { name = "opentelemetry-exporter-otlp-proto-http" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fc/d3/8156cc14e8f4573a3572ee7f30badc7aabd02961a09acc72ab5f2c789ef1/opentelemetry_exporter_otlp-1.27.0.tar.gz", hash = "sha256:4a599459e623868cc95d933c301199c2367e530f089750e115599fccd67cb2a1", size = 6166 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/59/6d/95e1fc2c8d945a734db32e87a5aa7a804f847c1657a21351df9338bd1c9c/opentelemetry_exporter_otlp-1.27.0-py3-none-any.whl", hash = "sha256:7688791cbdd951d71eb6445951d1cfbb7b6b2d7ee5948fac805d404802931145", size = 7001 },
+]
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-common"
+version = "1.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "opentelemetry-proto" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/cd/2e/7eaf4ba595fb5213cf639c9158dfb64aacb2e4c7d74bfa664af89fa111f4/opentelemetry_exporter_otlp_proto_common-1.27.0.tar.gz", hash = "sha256:159d27cf49f359e3798c4c3eb8da6ef4020e292571bd8c5604a2a573231dd5c8", size = 17860 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/41/27/4610ab3d9bb3cde4309b6505f98b3aabca04a26aa480aa18cede23149837/opentelemetry_exporter_otlp_proto_common-1.27.0-py3-none-any.whl", hash = "sha256:675db7fffcb60946f3a5c43e17d1168a3307a94a930ecf8d2ea1f286f3d4f79a", size = 17848 },
+]
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-grpc"
+version = "1.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "deprecated" },
+    { name = "googleapis-common-protos" },
+    { name = "grpcio" },
+    { name = "opentelemetry-api" },
+    { name = "opentelemetry-exporter-otlp-proto-common" },
+    { name = "opentelemetry-proto" },
+    { name = "opentelemetry-sdk" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/d0/c1e375b292df26e0ffebf194e82cd197e4c26cc298582bda626ce3ce74c5/opentelemetry_exporter_otlp_proto_grpc-1.27.0.tar.gz", hash = "sha256:af6f72f76bcf425dfb5ad11c1a6d6eca2863b91e63575f89bb7b4b55099d968f", size = 26244 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/8d/80/32217460c2c64c0568cea38410124ff680a9b65f6732867bbf857c4d8626/opentelemetry_exporter_otlp_proto_grpc-1.27.0-py3-none-any.whl", hash = "sha256:56b5bbd5d61aab05e300d9d62a6b3c134827bbd28d0b12f2649c2da368006c9e", size = 18541 },
+]
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-http"
+version = "1.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "deprecated" },
+    { name = "googleapis-common-protos" },
+    { name = "opentelemetry-api" },
+    { name = "opentelemetry-exporter-otlp-proto-common" },
+    { name = "opentelemetry-proto" },
+    { name = "opentelemetry-sdk" },
+    { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/31/0a/f05c55e8913bf58a033583f2580a0ec31a5f4cf2beacc9e286dcb74d6979/opentelemetry_exporter_otlp_proto_http-1.27.0.tar.gz", hash = "sha256:2103479092d8eb18f61f3fbff084f67cc7f2d4a7d37e75304b8b56c1d09ebef5", size = 15059 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/2d/8d/4755884afc0b1db6000527cac0ca17273063b6142c773ce4ecd307a82e72/opentelemetry_exporter_otlp_proto_http-1.27.0-py3-none-any.whl", hash = "sha256:688027575c9da42e179a69fe17e2d1eba9b14d81de8d13553a21d3114f3b4d75", size = 17203 },
+]
+
+[[package]]
+name = "opentelemetry-instrumentation"
+version = "0.48b0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "opentelemetry-api" },
+    { name = "setuptools" },
+    { name = "wrapt" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/04/0e/d9394839af5d55c8feb3b22cd11138b953b49739b20678ca96289e30f904/opentelemetry_instrumentation-0.48b0.tar.gz", hash = "sha256:94929685d906380743a71c3970f76b5f07476eea1834abd5dd9d17abfe23cc35", size = 24724 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0a/7f/405c41d4f359121376c9d5117dcf68149b8122d3f6c718996d037bd4d800/opentelemetry_instrumentation-0.48b0-py3-none-any.whl", hash = "sha256:a69750dc4ba6a5c3eb67986a337185a25b739966d80479befe37b546fc870b44", size = 29449 },
+]
+
+[[package]]
+name = "opentelemetry-proto"
+version = "1.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "protobuf" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/9a/59/959f0beea798ae0ee9c979b90f220736fbec924eedbefc60ca581232e659/opentelemetry_proto-1.27.0.tar.gz", hash = "sha256:33c9345d91dafd8a74fc3d7576c5a38f18b7fdf8d02983ac67485386132aedd6", size = 34749 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/94/56/3d2d826834209b19a5141eed717f7922150224d1a982385d19a9444cbf8d/opentelemetry_proto-1.27.0-py3-none-any.whl", hash = "sha256:b133873de5581a50063e1e4b29cdcf0c5e253a8c2d8dc1229add20a4c3830ace", size = 52464 },
+]
+
 [[package]]
 name = "opentelemetry-sdk"
 version = "1.27.0"
@@ -3374,6 +4681,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/70/7f/f2d346819a273653825e7c92dc26418c8da506003c9fc1dfe8157e733b2e/orjson-3.10.14-cp312-cp312-win_amd64.whl", hash = "sha256:175cafd322e458603e8ce73510a068d16b6e6f389c13f69bf16de0e843d7d406", size = 133663 },
 ]
 
+[[package]]
+name = "outcome"
+version = "1.3.0.post0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "attrs" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/55/8b/5ab7257531a5d830fc8000c476e63c935488d74609b50f9384a643ec0a62/outcome-1.3.0.post0-py2.py3-none-any.whl", hash = "sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b", size = 10692 },
+]
+
 [[package]]
 name = "overrides"
 version = "7.7.0"
@@ -3427,6 +4746,19 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/29/d4/1244ab8edf173a10fd601f7e13b9566c1b525c4f365d6bee918e68381889/pandas-2.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:59ef3764d0fe818125a5097d2ae867ca3fa64df032331b7e0917cf5d7bf66b13", size = 11504248 },
 ]
 
+[[package]]
+name = "pandas-stubs"
+version = "2.2.3.241126"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "numpy" },
+    { name = "types-pytz" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/90/86/93c545d149c3e1fe1c4c55478cc3a69859d0ea3467e1d9892e9eb28cb1e7/pandas_stubs-2.2.3.241126.tar.gz", hash = "sha256:cf819383c6d9ae7d4dabf34cd47e1e45525bb2f312e6ad2939c2c204cb708acd", size = 104204 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/6f/ab/ed42acf15bab2e86e5c49fad4aa038315233c4c2d22f41b49faa4d837516/pandas_stubs-2.2.3.241126-py3-none-any.whl", hash = "sha256:74aa79c167af374fe97068acc90776c0ebec5266a6e5c69fe11e9c2cf51f2267", size = 158280 },
+]
+
 [[package]]
 name = "parse"
 version = "1.20.2"
@@ -3445,6 +4777,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 },
 ]
 
+[[package]]
+name = "pastel"
+version = "0.2.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955 },
+]
+
 [[package]]
 name = "pathable"
 version = "0.4.4"
@@ -3475,6 +4816,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/87/2b/b50d3d08ea0fc419c183a84210571eba005328efa62b6b98bc28e9ead32a/patsy-1.0.1-py2.py3-none-any.whl", hash = "sha256:751fb38f9e97e62312e921a1954b81e1bb2bcda4f5eeabaf94db251ee791509c", size = 232923 },
 ]
 
+[[package]]
+name = "pbr"
+version = "6.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b2/35/80cf8f6a4f34017a7fe28242dc45161a1baa55c41563c354d8147e8358b2/pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24", size = 124032 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/1d/44/6a65ecd630393d47ad3e7d5354768cb7f9a10b3a0eb2cd8c6f52b28211ee/pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a", size = 108529 },
+]
+
 [[package]]
 name = "pdfminer-six"
 version = "20240706"
@@ -3548,6 +4898,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/41/67/936f9814bdd74b2dfd4822f1f7725ab5d8ff4103919a1664eb4874c58b2f/pillow-11.1.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4637b88343166249fe8aa94e7c4a62a180c4b3898283bb5d3d2fd5fe10d8e4e0", size = 2626353 },
 ]
 
+[[package]]
+name = "pip"
+version = "24.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/f4/b1/b422acd212ad7eedddaf7981eee6e5de085154ff726459cf2da7c5a184c1/pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99", size = 1931073 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ef/7d/500c9ad20238fcfcb4cb9243eede163594d7020ce87bd9610c9e02771876/pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed", size = 1822182 },
+]
+
 [[package]]
 name = "platformdirs"
 version = "4.3.6"
@@ -3584,12 +4943,40 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
 ]
 
+[[package]]
+name = "poethepoet"
+version = "0.32.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pastel" },
+    { name = "pyyaml" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/d1/10/11f929bad564b2dbc5c119ecf0f37456ac24538bb4a70c76f140a2aa695a/poethepoet-0.32.1.tar.gz", hash = "sha256:471e1a025812dcd3d2997e30989681be5ab0a49232ee5fba94859629671c9584", size = 61391 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/85/a5/fc26dd508f33809bdd3823a0170e492fe44ad7e097c32c4a52e16cf3ecb0/poethepoet-0.32.1-py3-none-any.whl", hash = "sha256:d1e0a52a2f677870fac17dfb26bfe4910242756ac821443ef31f90ad26227c2d", size = 81729 },
+]
+
+[[package]]
+name = "polars"
+version = "1.19.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/26/d9/66ada2204483c4c4d83898ade77eacd5fbef26ae4975a0d7d5de134ca46a/polars-1.19.0.tar.gz", hash = "sha256:b52ada5c43fcdadf64f282522198c5549ee4e46ea57d236a4d7e572643070d9d", size = 4267947 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c0/7d/e8645281281d44d96752443366ceef2df76c9c1e17dce040111abb6a4a12/polars-1.19.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:51c01837268a1aa41785e60ed7d3363d4b52f652ab0eef4981f887bdfa2e9ca7", size = 29472039 },
+    { url = "https://files.pythonhosted.org/packages/d7/fb/7e5054598d6bb7a47e4ca086797bae61270f7d570350cf779dd97384d913/polars-1.19.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:20f8235e810f6ee795d7a215a3560945e6a1b57d017f87ba0c8542dced1fc665", size = 26150541 },
+    { url = "https://files.pythonhosted.org/packages/ba/ba/6d715730c28b035abd308fc2cf0fcbae0cedea6216797e83ce4a9a96c6d4/polars-1.19.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0ea51f7b3553652bf0d53f3b925e969a898d4feb9980acecf8e3037d696903", size = 32751173 },
+    { url = "https://files.pythonhosted.org/packages/ea/9a/bee8ab37ab82b8eea75170afa3b37ea7e1df74e4c4da8f6c93b3009977fd/polars-1.19.0-cp39-abi3-manylinux_2_24_aarch64.whl", hash = "sha256:30305ef4e1b634c67a5d985832296fade9908482c5b1abb0100800808b2d090e", size = 29704437 },
+    { url = "https://files.pythonhosted.org/packages/57/ec/74afa5699e37e03e3acc7f241f4e2c3e8c91847524005424d9cf038b3034/polars-1.19.0-cp39-abi3-win_amd64.whl", hash = "sha256:de4aa45e24f8f94a1da9cc6031a7db6fa65ac7de8246fac0bc581ebb427d0643", size = 32846039 },
+    { url = "https://files.pythonhosted.org/packages/cf/5b/c6f6c70ddc9d3070dee65f4640437cb84ccb4cca04f7a81b01db15329ae3/polars-1.19.0-cp39-abi3-win_arm64.whl", hash = "sha256:d7ca7aeb63fa22c0a00f6cfa95dd5252c249e83dd4d1b954583a59f97a8e407b", size = 29029208 },
+]
+
 [[package]]
 name = "portalocker"
 version = "2.10.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "pywin32", marker = "platform_system == 'Windows'" },
+    { name = "pywin32", marker = "sys_platform == 'win32'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 }
 wheels = [
@@ -3857,6 +5244,15 @@ dependencies = [
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/ee/52/9aa428633ef5aba4b096b2b2f8d046ece613cecab28b4ceed54126d25ea5/pybars4-0.9.13.tar.gz", hash = "sha256:425817da20d4ad320bc9b8e77a60cab1bb9d3c677df3dce224925c3310fcd635", size = 29907 }
 
+[[package]]
+name = "pycodestyle"
+version = "2.12.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284 },
+]
+
 [[package]]
 name = "pycparser"
 version = "2.22"
@@ -3954,6 +5350,25 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b4/46/93416fdae86d40879714f72956ac14df9c7b76f7d41a4d68aa9f71a0028b/pydantic_settings-2.7.1-py3-none-any.whl", hash = "sha256:590be9e6e24d06db33a4262829edef682500ef008565a969c73d39d5f8bfb3fd", size = 29718 },
 ]
 
+[[package]]
+name = "pydata-sphinx-theme"
+version = "0.15.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "accessible-pygments" },
+    { name = "babel" },
+    { name = "beautifulsoup4" },
+    { name = "docutils" },
+    { name = "packaging" },
+    { name = "pygments" },
+    { name = "sphinx" },
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/67/ea/3ab478cccacc2e8ef69892c42c44ae547bae089f356c4b47caf61730958d/pydata_sphinx_theme-0.15.4.tar.gz", hash = "sha256:7762ec0ac59df3acecf49fd2f889e1b4565dbce8b88b2e29ee06fdd90645a06d", size = 2400673 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e7/d3/c622950d87a2ffd1654208733b5bd1c5645930014abed8f4c0d74863988b/pydata_sphinx_theme-0.15.4-py3-none-any.whl", hash = "sha256:2136ad0e9500d0949f96167e63f3e298620040aea8f9c74621959eda5d4cf8e6", size = 4640157 },
+]
+
 [[package]]
 name = "pydub"
 version = "0.25.1"
@@ -4046,6 +5461,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/1c/a7/c8a2d361bf89c0d9577c934ebb7421b25dc84bf3a8e3ac0a40aed9acc547/pyparsing-3.2.1-py3-none-any.whl", hash = "sha256:506ff4f4386c4cec0590ec19e6302d3aedb992fdc02c761e90416f158dacf8e1", size = 107716 },
 ]
 
+[[package]]
+name = "pypdf"
+version = "5.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6b/9a/72d74f05f64895ebf1c7f6646cf7fe6dd124398c5c49240093f92d6f0fdd/pypdf-5.1.0.tar.gz", hash = "sha256:425a129abb1614183fd1aca6982f650b47f8026867c0ce7c4b9f281c443d2740", size = 5011381 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/04/fc/6f52588ac1cb4400a7804ef88d0d4e00cfe57a7ac6793ec3b00de5a8758b/pypdf-5.1.0-py3-none-any.whl", hash = "sha256:3bd4f503f4ebc58bae40d81e81a9176c400cbbac2ba2d877367595fb524dfdfc", size = 297976 },
+]
+
 [[package]]
 name = "pyreadline3"
 version = "3.5.4"
@@ -4055,6 +5482,28 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/5a/dc/491b7661614ab97483abf2056be1deee4dc2490ecbf7bff9ab5cdbac86e1/pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6", size = 83178 },
 ]
 
+[[package]]
+name = "pyright"
+version = "1.1.389"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "nodeenv" },
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/4e/9a5ab8745e7606b88c2c7ca223449ac9d82a71fd5e31df47b453f2cb39a1/pyright-1.1.389.tar.gz", hash = "sha256:716bf8cc174ab8b4dcf6828c3298cac05c5ed775dda9910106a5dcfe4c7fe220", size = 21940 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/1b/26/c288cabf8cfc5a27e1aa9e5029b7682c0f920b8074f45d22bf844314d66a/pyright-1.1.389-py3-none-any.whl", hash = "sha256:41e9620bba9254406dc1f621a88ceab5a88af4c826feb4f614d95691ed243a60", size = 18581 },
+]
+
+[[package]]
+name = "pysocks"
+version = "1.7.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/bd/11/293dd436aea955d45fc4e8a35b6ae7270f5b8e00b53cf6c024c83b657a11/PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0", size = 284429 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/8d/59/b4572118e098ac8e46e399a1dd0f2d85403ce8bbaad9ec79373ed6badaf9/PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5", size = 16725 },
+]
+
 [[package]]
 name = "pytest"
 version = "8.3.4"
@@ -4072,6 +5521,56 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/11/92/76a1c94d3afee238333bc0a42b82935dd8f9cf8ce9e336ff87ee14d9e1cf/pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6", size = 343083 },
 ]
 
+[[package]]
+name = "pytest-asyncio"
+version = "0.25.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/df/adcc0d60f1053d74717d21d58c0048479e9cab51464ce0d2965b086bd0e2/pytest_asyncio-0.25.2.tar.gz", hash = "sha256:3f8ef9a98f45948ea91a0ed3dc4268b5326c0e7bce73892acc654df4262ad45f", size = 53950 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/61/d8/defa05ae50dcd6019a95527200d3b3980043df5aa445d40cb0ef9f7f98ab/pytest_asyncio-0.25.2-py3-none-any.whl", hash = "sha256:0d0bb693f7b99da304a0634afc0a4b19e49d5e0de2d670f38dc4bfa5727c5075", size = 19400 },
+]
+
+[[package]]
+name = "pytest-cov"
+version = "6.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "coverage", extra = ["toml"] },
+    { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 },
+]
+
+[[package]]
+name = "pytest-mock"
+version = "3.14.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c6/90/a955c3ab35ccd41ad4de556596fa86685bf4fc5ffcc62d22d856cfd4e29a/pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0", size = 32814 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/f2/3b/b26f90f74e2986a82df6e7ac7e319b8ea7ccece1caec9f8ab6104dc70603/pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f", size = 9863 },
+]
+
+[[package]]
+name = "pytest-xdist"
+version = "3.6.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "execnet" },
+    { name = "pytest" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/41/c4/3c310a19bc1f1e9ef50075582652673ef2bfc8cd62afef9585683821902f/pytest_xdist-3.6.1.tar.gz", hash = "sha256:ead156a4db231eec769737f57668ef58a2084a34b2e55c4a8fa20d861107300d", size = 84060 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/6d/82/1d96bf03ee4c0fdc3c0cbe61470070e659ca78dc0086fb88b66c185e2449/pytest_xdist-3.6.1-py3-none-any.whl", hash = "sha256:9ed4adfb68a016610848639bb7e02c9352d5d9f03d04809919e2dafc3be4cca7", size = 46108 },
+]
+
 [[package]]
 name = "python-dateutil"
 version = "2.9.0.post0"
@@ -4093,6 +5592,27 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
 ]
 
+[[package]]
+name = "python-engineio"
+version = "4.11.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "simple-websocket" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/52/e0/a9e0fe427ce7f1b7dbf9531fa00ffe4b557c4a7bc8e71891c115af123170/python_engineio-4.11.2.tar.gz", hash = "sha256:145bb0daceb904b4bb2d3eb2d93f7dbb7bb87a6a0c4f20a94cc8654dec977129", size = 91381 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/07/8f/978a0b913e3f8ad33a9a2fe204d32efe3d1ee34ecb1f2829c1cfbdd92082/python_engineio-4.11.2-py3-none-any.whl", hash = "sha256:f0971ac4c65accc489154fe12efd88f53ca8caf04754c46a66e85f5102ef22ad", size = 59239 },
+]
+
+[[package]]
+name = "python-multipart"
+version = "0.0.18"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/b4/86/b6b38677dec2e2e7898fc5b6f7e42c2d011919a92d25339451892f27b89c/python_multipart-0.0.18.tar.gz", hash = "sha256:7a68db60c8bfb82e460637fa4750727b45af1d5e2ed215593f917f64694d34fe", size = 36622 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/13/6b/b60f47101ba2cac66b4a83246630e68ae9bbe2e614cbae5f4465f46dee13/python_multipart-0.0.18-py3-none-any.whl", hash = "sha256:efe91480f485f6a361427a541db4796f9e1591afc0fb8e7a4ba06bfbc6708996", size = 24389 },
+]
+
 [[package]]
 name = "python-pptx"
 version = "1.0.2"
@@ -4108,6 +5628,31 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d9/4f/00be2196329ebbff56ce564aa94efb0fbc828d00de250b1980de1a34ab49/python_pptx-1.0.2-py3-none-any.whl", hash = "sha256:160838e0b8565a8b1f67947675886e9fea18aa5e795db7ae531606d68e785cba", size = 472788 },
 ]
 
+[[package]]
+name = "python-slugify"
+version = "8.0.4"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "text-unidecode" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/87/c7/5e1547c44e31da50a460df93af11a535ace568ef89d7a811069ead340c4a/python-slugify-8.0.4.tar.gz", hash = "sha256:59202371d1d05b54a9e7720c5e038f928f45daaffe41dd10822f3907b937c856", size = 10921 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a4/62/02da182e544a51a5c3ccf4b03ab79df279f9c60c5e82d5e8bec7ca26ac11/python_slugify-8.0.4-py2.py3-none-any.whl", hash = "sha256:276540b79961052b66b7d116620b36518847f52d5fd9e3a70164fc8c50faa6b8", size = 10051 },
+]
+
+[[package]]
+name = "python-socketio"
+version = "5.12.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "bidict" },
+    { name = "python-engineio" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ce/d0/40ed38076e8aee94785d546d3e3a1cae393da5806a8530be877187e2875f/python_socketio-5.12.1.tar.gz", hash = "sha256:0299ff1f470b676c09c1bfab1dead25405077d227b2c13cf217a34dadc68ba9c", size = 119991 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/8a/a3/c69806f30dd81df5a99d592e7db4c930c3a9b098555aa97b0eb866b20b11/python_socketio-5.12.1-py3-none-any.whl", hash = "sha256:24a0ea7cfff0e021eb28c68edbf7914ee4111bdf030b95e4d250c4dc9af7a386", size = 76947 },
+]
+
 [[package]]
 name = "pytz"
 version = "2024.2"
@@ -4225,7 +5770,8 @@ name = "redis"
 version = "5.2.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "async-timeout", marker = "python_full_version < '3.11.3'" },
+    { name = "async-timeout", version = "4.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+    { name = "async-timeout", version = "5.0.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.11.3'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/47/da/d283a37303a995cd36f8b92db85135153dc4f7a8e4441aa827721b442cfb/redis-5.2.1.tar.gz", hash = "sha256:16f2e22dff21d5125e8481515e386711a34cbec50f0e44413dd7d9c060a54e0f", size = 4608355 }
 wheels = [
@@ -4314,6 +5860,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 },
 ]
 
+[[package]]
+name = "requests-file"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/72/97/bf44e6c6bd8ddbb99943baf7ba8b1a8485bcd2fe0e55e5708d7fee4ff1ae/requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658", size = 6891 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d7/25/dd878a121fcfdf38f52850f11c512e13ec87c2ea72385933818e5b6c15ce/requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c", size = 4244 },
+]
+
 [[package]]
 name = "requests-toolbelt"
 version = "1.0.0"
@@ -4470,6 +6028,30 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d7/8f/c3654f6f1ddb75daf3922c3d8fc6005b1ab56671ad56ffb874d908bfa668/ruamel.yaml.clib-0.2.12-cp312-cp312-win_amd64.whl", hash = "sha256:0467c5965282c62203273b838ae77c0d29d7638c8a4e3a1c8bdd3602c10904e4", size = 115523 },
 ]
 
+[[package]]
+name = "ruff"
+version = "0.4.8"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/0f/6b/4545638200466af8b9407bd0d5bea1ce426328eaa9714f8d3ef1a43fc0e6/ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268", size = 2559790 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e6/fd/cbdfeba4f72856853705b4dfc01c232fd6000cdbbde801224783de65c2a6/ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066", size = 8547521 },
+    { url = "https://files.pythonhosted.org/packages/b2/8d/8930e04a82f376b99db57d8d1c86bd35c06496e77f58f6b2cdb388cd12d9/ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913", size = 8149146 },
+    { url = "https://files.pythonhosted.org/packages/59/82/63d590c95025d526acc64803ab783f457ba15b3e16bea5bfb4b7ba9bf105/ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3", size = 8192701 },
+    { url = "https://files.pythonhosted.org/packages/70/f4/97e142f3c9cb2c886798821e31136b58a6095e068b5bf6a9667f45dcf70b/ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb", size = 7578485 },
+    { url = "https://files.pythonhosted.org/packages/fd/46/2b9addf3e3078c6d2c78135480f9dbf104257cfa6736d65154e9c7f64a34/ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764", size = 8768085 },
+    { url = "https://files.pythonhosted.org/packages/b5/bf/b7bcec679c67a74d4df5ecaa6e09352d4dd14a365a1d0ce76deb6f5d8a56/ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883", size = 9439095 },
+    { url = "https://files.pythonhosted.org/packages/cb/46/1a7bfa8f739116ec48d737d78d99b6e1c3c6307992b17b11bc8a44ee393f/ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199", size = 9060426 },
+    { url = "https://files.pythonhosted.org/packages/ad/6b/e82233a81554df12a3508a25a5068d005fb7b69b14cc4194237e7b4c5fcf/ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b", size = 10250216 },
+    { url = "https://files.pythonhosted.org/packages/21/77/9d9c536d8544d8b1b2fe1fcd5e3e190b946d91dc00a8956aa5fe88cb264b/ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45", size = 8797490 },
+    { url = "https://files.pythonhosted.org/packages/95/90/a614ec4ee32a61dcd76c5d77ef5c336acac447cf731d81313e42dcbc34ed/ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a", size = 8092448 },
+    { url = "https://files.pythonhosted.org/packages/1f/5b/d0a5ddf505593bacb52f386b0b92533dc2e87658a59ec55fe5b72890f1af/ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc", size = 7573842 },
+    { url = "https://files.pythonhosted.org/packages/da/4a/d6af0c924514ebc588474b5002ac9bc6cc0b2328d3633c1b10b0227032c1/ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed", size = 8358130 },
+    { url = "https://files.pythonhosted.org/packages/49/c4/3fbfb5a0020c9f67439dcef5a6e4f6a4f3430a059eaf40b624c00aa31bfa/ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa", size = 8842486 },
+    { url = "https://files.pythonhosted.org/packages/a5/e6/c18211dd3fad5a1da66a1bd7a00e3bdc7541fa997adeeb087c2147f1e18a/ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9", size = 7832464 },
+    { url = "https://files.pythonhosted.org/packages/95/b7/5b64aba350763aff321463e775f9daee9ad575750ebdb9f60f86f682f913/ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d", size = 8580070 },
+    { url = "https://files.pythonhosted.org/packages/fe/f1/3db1590be946c14d86ac0cc8422e5808500903592b7ca09a097e425b1dba/ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780", size = 7944828 },
+]
+
 [[package]]
 name = "s3transfer"
 version = "0.11.1"
@@ -4576,6 +6158,23 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914 },
 ]
 
+[[package]]
+name = "selenium"
+version = "4.27.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "certifi" },
+    { name = "trio" },
+    { name = "trio-websocket" },
+    { name = "typing-extensions" },
+    { name = "urllib3", extra = ["socks"] },
+    { name = "websocket-client" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/44/8c/62c47c91072aa03af1c3b7d7f1c59b987db41c9fec0f158fb03a0da51aa6/selenium-4.27.1.tar.gz", hash = "sha256:5296c425a75ff1b44d0d5199042b36a6d1ef76c04fb775b97b40be739a9caae2", size = 973526 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a6/1e/5f1a5dd2a28528c4b3ec6e076b58e4c035810c805328f9936123283ca14e/selenium-4.27.1-py3-none-any.whl", hash = "sha256:b89b1f62b5cfe8025868556fe82360d6b649d464f75d2655cb966c8f8447ea18", size = 9707007 },
+]
+
 [[package]]
 name = "semantic-kernel"
 version = "1.18.2"
@@ -4667,6 +6266,12 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/69/8a/b9dc7678803429e4a3bc9ba462fa3dd9066824d3c607490235c6a796be5a/setuptools-75.8.0-py3-none-any.whl", hash = "sha256:e3982f444617239225d675215d51f6ba05f845d4eec313da4418fdbb56fb27e3", size = 1228782 },
 ]
 
+[[package]]
+name = "sgmllib3k"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/9e/bd/3704a8c3e0942d711c1299ebf7b9091930adae6675d7c8f476a7ce48653c/sgmllib3k-1.0.0.tar.gz", hash = "sha256:7868fb1c8bfa764c1ac563d3cf369c381d1325d36124933a726f29fcdaa812e9", size = 5750 }
+
 [[package]]
 name = "shapely"
 version = "2.0.6"
@@ -4705,6 +6310,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
 ]
 
+[[package]]
+name = "simple-websocket"
+version = "1.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "wsproto" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842 },
+]
+
 [[package]]
 name = "simsimd"
 version = "6.2.1"
@@ -4765,55 +6382,230 @@ wheels = [
 ]
 
 [[package]]
-name = "six"
-version = "1.17.0"
+name = "six"
+version = "1.17.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 },
+]
+
+[[package]]
+name = "smart-open"
+version = "7.1.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "wrapt" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/21/30/1f41c3d3b8cec82024b4b277bfd4e5b18b765ae7279eb9871fa25c503778/smart_open-7.1.0.tar.gz", hash = "sha256:a4f09f84f0f6d3637c6543aca7b5487438877a21360e7368ccf1f704789752ba", size = 72044 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7a/18/9a8d9f01957aa1f8bbc5676d54c2e33102d247e146c1a3679d3bd5cc2e3a/smart_open-7.1.0-py3-none-any.whl", hash = "sha256:4b8489bb6058196258bafe901730c7db0dcf4f083f316e97269c66f45502055b", size = 61746 },
+]
+
+[[package]]
+name = "sniffio"
+version = "1.3.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
+]
+
+[[package]]
+name = "snowballstemmer"
+version = "2.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/44/7b/af302bebf22c749c56c9c3e8ae13190b5b5db37a33d9068652e8f73b7089/snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1", size = 86699 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ed/dc/c02e01294f7265e63a7315fe086dd1df7dacb9f840a804da846b96d01b96/snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a", size = 93002 },
+]
+
+[[package]]
+name = "sortedcontainers"
+version = "2.4.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575 },
+]
+
+[[package]]
+name = "soupsieve"
+version = "2.6"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
+]
+
+[[package]]
+name = "speechrecognition"
+version = "3.14.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ce/67/b91500f0796806659c37ba4da26750148ea98cd4e00d951facfdf4f440b3/speechrecognition-3.14.0.tar.gz", hash = "sha256:8f23d0125422fac358a05697ceffb5d7387a3f699fc2dcf829ee692fb15471c2", size = 32860450 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/5e/25/447b3a61afbc1d7e713ba56df0156aab1450442db752f1e6741d6a9f41df/SpeechRecognition-3.14.0-py3-none-any.whl", hash = "sha256:28303ae2b6abc13408963a91f838996f181f1c256936f94b8c021b51fcd4a3f5", size = 32852277 },
+]
+
+[[package]]
+name = "sphinx"
+version = "8.1.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "alabaster" },
+    { name = "babel" },
+    { name = "colorama", marker = "sys_platform == 'win32'" },
+    { name = "docutils" },
+    { name = "imagesize" },
+    { name = "jinja2" },
+    { name = "packaging" },
+    { name = "pygments" },
+    { name = "requests" },
+    { name = "snowballstemmer" },
+    { name = "sphinxcontrib-applehelp" },
+    { name = "sphinxcontrib-devhelp" },
+    { name = "sphinxcontrib-htmlhelp" },
+    { name = "sphinxcontrib-jsmath" },
+    { name = "sphinxcontrib-qthelp" },
+    { name = "sphinxcontrib-serializinghtml" },
+    { name = "tomli", marker = "python_full_version < '3.11'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/26/60/1ddff83a56d33aaf6f10ec8ce84b4c007d9368b21008876fceda7e7381ef/sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2", size = 3487125 },
+]
+
+[[package]]
+name = "sphinx-autobuild"
+version = "2024.10.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "colorama" },
+    { name = "sphinx" },
+    { name = "starlette" },
+    { name = "uvicorn" },
+    { name = "watchfiles" },
+    { name = "websockets" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a5/2c/155e1de2c1ba96a72e5dba152c509a8b41e047ee5c2def9e9f0d812f8be7/sphinx_autobuild-2024.10.3.tar.gz", hash = "sha256:248150f8f333e825107b6d4b86113ab28fa51750e5f9ae63b59dc339be951fb1", size = 14023 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/18/c0/eba125db38c84d3c74717008fd3cb5000b68cd7e2cbafd1349c6a38c3d3b/sphinx_autobuild-2024.10.3-py3-none-any.whl", hash = "sha256:158e16c36f9d633e613c9aaf81c19b0fc458ca78b112533b20dafcda430d60fa", size = 11908 },
+]
+
+[[package]]
+name = "sphinx-copybutton"
+version = "0.5.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "sphinx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz", hash = "sha256:4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd", size = 23039 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl", hash = "sha256:fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e", size = 13343 },
+]
+
+[[package]]
+name = "sphinx-design"
+version = "0.6.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "sphinx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/2b/69/b34e0cb5336f09c6866d53b4a19d76c227cdec1bbc7ac4de63ca7d58c9c7/sphinx_design-0.6.1.tar.gz", hash = "sha256:b44eea3719386d04d765c1a8257caca2b3e6f8421d7b3a5e742c0fd45f84e632", size = 2193689 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c6/43/65c0acbd8cc6f50195a3a1fc195c404988b15c67090e73c7a41a9f57d6bd/sphinx_design-0.6.1-py3-none-any.whl", hash = "sha256:b11f37db1a802a183d61b159d9a202314d4d2fe29c163437001324fe2f19549c", size = 2215338 },
+]
+
+[[package]]
+name = "sphinxcontrib-apidoc"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pbr" },
+    { name = "sphinx" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/52/8c/a4fe93b51a1026c217731337cfe50569b8521d3e254dd451126bed208cd8/sphinxcontrib-apidoc-0.5.0.tar.gz", hash = "sha256:65efcd92212a5f823715fb95ee098b458a6bb09a5ee617d9ed3dead97177cd55", size = 16117 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/1c/35/453ba8b0f407b9b86520eba5122fe28e87230266cfae9524a623b524485e/sphinxcontrib_apidoc-0.5.0-py3-none-any.whl", hash = "sha256:c671d644d6dc468be91b813dcddf74d87893bff74fe8f1b8b01b69408f0fb776", size = 8603 },
+]
+
+[[package]]
+name = "sphinxcontrib-applehelp"
+version = "2.0.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031 }
+sdist = { url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1", size = 20053 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050 },
+    { url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5", size = 119300 },
 ]
 
 [[package]]
-name = "smart-open"
-version = "7.1.0"
+name = "sphinxcontrib-devhelp"
+version = "2.0.0"
 source = { registry = "https://pypi.org/simple" }
-dependencies = [
-    { name = "wrapt" },
+sdist = { url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad", size = 12967 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2", size = 82530 },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/21/30/1f41c3d3b8cec82024b4b277bfd4e5b18b765ae7279eb9871fa25c503778/smart_open-7.1.0.tar.gz", hash = "sha256:a4f09f84f0f6d3637c6543aca7b5487438877a21360e7368ccf1f704789752ba", size = 72044 }
+
+[[package]]
+name = "sphinxcontrib-htmlhelp"
+version = "2.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9", size = 22617 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/7a/18/9a8d9f01957aa1f8bbc5676d54c2e33102d247e146c1a3679d3bd5cc2e3a/smart_open-7.1.0-py3-none-any.whl", hash = "sha256:4b8489bb6058196258bafe901730c7db0dcf4f083f316e97269c66f45502055b", size = 61746 },
+    { url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8", size = 98705 },
 ]
 
 [[package]]
-name = "sniffio"
-version = "1.3.1"
+name = "sphinxcontrib-jsmath"
+version = "1.0.1"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
+sdist = { url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8", size = 5787 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
+    { url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178", size = 5071 },
 ]
 
 [[package]]
-name = "soupsieve"
-version = "2.6"
+name = "sphinxcontrib-qthelp"
+version = "2.0.0"
 source = { registry = "https://pypi.org/simple" }
-sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 }
+sdist = { url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab", size = 17165 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 },
+    { url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb", size = 88743 },
 ]
 
 [[package]]
-name = "speechrecognition"
-version = "3.14.0"
+name = "sphinxcontrib-serializinghtml"
+version = "2.0.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d", size = 16080 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331", size = 92072 },
+]
+
+[[package]]
+name = "sphinxext-rediraffe"
+version = "0.2.7"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "typing-extensions" },
+    { name = "sphinx" },
 ]
-sdist = { url = "https://files.pythonhosted.org/packages/ce/67/b91500f0796806659c37ba4da26750148ea98cd4e00d951facfdf4f440b3/speechrecognition-3.14.0.tar.gz", hash = "sha256:8f23d0125422fac358a05697ceffb5d7387a3f699fc2dcf829ee692fb15471c2", size = 32860450 }
+sdist = { url = "https://files.pythonhosted.org/packages/1f/b4/e5fbb493f796430230189a1ce5f9beff1ac1b98619fc71ed35deca6059a5/sphinxext-rediraffe-0.2.7.tar.gz", hash = "sha256:651dcbfae5ffda9ffd534dfb8025f36120e5efb6ea1a33f5420023862b9f725d", size = 8735 }
 wheels = [
-    { url = "https://files.pythonhosted.org/packages/5e/25/447b3a61afbc1d7e713ba56df0156aab1450442db752f1e6741d6a9f41df/SpeechRecognition-3.14.0-py3-none-any.whl", hash = "sha256:28303ae2b6abc13408963a91f838996f181f1c256936f94b8c021b51fcd4a3f5", size = 32852277 },
+    { url = "https://files.pythonhosted.org/packages/76/4f/c8797e796199e55cf6c8979ecdf5f4b09b81e93f87b3193c759faea63263/sphinxext_rediraffe-0.2.7-py3-none-any.whl", hash = "sha256:9e430a52d4403847f4ffb3a8dd6dfc34a9fe43525305131f52ed899743a5fd8c", size = 8267 },
+]
+
+[[package]]
+name = "spider-client"
+version = "0.0.27"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "requests" },
 ]
+sdist = { url = "https://files.pythonhosted.org/packages/70/fc/a2a4cc112c467f89921328d005c0ac2df9c81f62c8a6d445f747252f5856/spider-client-0.0.27.tar.gz", hash = "sha256:c3feaf5c491bd9a6c509efa0c8789452497073d9f68e70fc90e7626a6a8365aa", size = 5755 }
 
 [[package]]
 name = "sqlalchemy"
@@ -4852,6 +6644,11 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/3b/36/59cc97c365f2f79ac9f3f51446cae56dfd82c4f2dd98497e6be6de20fb91/SQLAlchemy-2.0.37-py3-none-any.whl", hash = "sha256:a8998bf9f8658bd3839cbc44ddbe982955641863da0c1efe5b00c1ab4f5c16b1", size = 1894113 },
 ]
 
+[package.optional-dependencies]
+asyncio = [
+    { name = "greenlet" },
+]
+
 [[package]]
 name = "sqlmodel"
 version = "0.0.22"
@@ -4924,6 +6721,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/59/9a/e466a1b887a1441141e52dbcc98152f013d85076576da6eed2357f2016ae/statsmodels-0.14.4-cp312-cp312-win_amd64.whl", hash = "sha256:7f7917a51766b4e074da283c507a25048ad29a18e527207883d73535e0dc6184", size = 9823866 },
 ]
 
+[[package]]
+name = "striprtf"
+version = "0.0.26"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/25/20/3d419008265346452d09e5dadfd5d045b64b40d8fc31af40588e6c76997a/striprtf-0.0.26.tar.gz", hash = "sha256:fdb2bba7ac440072d1c41eab50d8d74ae88f60a8b6575c6e2c7805dc462093aa", size = 6258 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a3/cf/0fea4f4ba3fc2772ac2419278aa9f6964124d4302117d61bc055758e000c/striprtf-0.0.26-py3-none-any.whl", hash = "sha256:8c8f9d32083cdc2e8bfb149455aa1cc5a4e0a035893bedc75db8b73becb3a1bb", size = 6914 },
+]
+
 [[package]]
 name = "sympy"
 version = "1.13.1"
@@ -4936,6 +6742,12 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b2/fe/81695a1aa331a842b582453b605175f419fe8540355886031328089d840a/sympy-1.13.1-py3-none-any.whl", hash = "sha256:db36cdc64bf61b9b24578b6f7bab1ecdd2452cf008f34faa33776680c26d66f8", size = 6189177 },
 ]
 
+[[package]]
+name = "syncer"
+version = "2.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/8d/dd/d4dd75843692690d81f0a4b929212a1614b25d4896aa7c72f4c3546c7e3d/syncer-2.0.3.tar.gz", hash = "sha256:4340eb54b54368724a78c5c0763824470201804fe9180129daf3635cb500550f", size = 11512 }
+
 [[package]]
 name = "tabulate"
 version = "0.9.0"
@@ -4945,6 +6757,20 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/40/44/4a5f08c96eb108af5cb50b41f76142f0afa346dfa99d5296fe7202a11854/tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f", size = 35252 },
 ]
 
+[[package]]
+name = "tavily-python"
+version = "0.5.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "httpx" },
+    { name = "requests" },
+    { name = "tiktoken" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ca/50/7f4acafe72ffd10d3578ddec76f993af5af81504bc7315ea54862f2705b9/tavily_python-0.5.0.tar.gz", hash = "sha256:2c60b88203b630e1b37fc711913a1090ced6719b3f21089f25ec06e9e1602822", size = 16455 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/90/99/05776f7150a5b3f8d853377144a3a634131964c0fce38307537674a9a674/tavily_python-0.5.0-py3-none-any.whl", hash = "sha256:e874f6a04a56cdda80a505fe0b4f5d61d25372bd52a83e6773926fb297dcaa29", size = 14361 },
+]
+
 [[package]]
 name = "tenacity"
 version = "9.0.0"
@@ -4954,6 +6780,77 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/b6/cb/b86984bed139586d01532a587464b5805f12e397594f19f931c4c2fbfa61/tenacity-9.0.0-py3-none-any.whl", hash = "sha256:93de0c98785b27fcf659856aa9f54bfbd399e29969b0621bc7f762bd441b4539", size = 28169 },
 ]
 
+[[package]]
+name = "text-unidecode"
+version = "1.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/e2/e9a00f0ccb71718418230718b3d900e71a5d16e701a3dae079a21e9cd8f8/text-unidecode-1.3.tar.gz", hash = "sha256:bad6603bb14d279193107714b288be206cac565dfa49aa5b105294dd5c4aab93", size = 76885 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/a6/a5/c0b6468d3824fe3fde30dbb5e1f687b291608f9473681bbf7dabbf5a87d7/text_unidecode-1.3-py2.py3-none-any.whl", hash = "sha256:1311f10e8b895935241623731c2ba64f4c455287888b18189350b67134a822e8", size = 78154 },
+]
+
+[[package]]
+name = "textual"
+version = "1.0.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "markdown-it-py", extra = ["linkify", "plugins"] },
+    { name = "platformdirs" },
+    { name = "rich" },
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/1f/b6/59b1de04bb4dca0f21ed7ba0b19309ed7f3f5de4396edf20cc2855e53085/textual-1.0.0.tar.gz", hash = "sha256:bec9fe63547c1c552569d1b75d309038b7d456c03f86dfa3706ddb099b151399", size = 1532733 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ac/bb/5fb6656c625019cd653d5215237d7cd6e0b12e7eae4195c3d1c91b2136fc/textual-1.0.0-py3-none-any.whl", hash = "sha256:2d4a701781c05104925e463ae370c630567c70c2880e92ab838052e3e23c986f", size = 660456 },
+]
+
+[[package]]
+name = "textual-dev"
+version = "1.7.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "click" },
+    { name = "msgpack" },
+    { name = "textual" },
+    { name = "textual-serve" },
+    { name = "typing-extensions" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/a1/d3/ed0b20f6de0af1b7062c402d59d256029c0daa055ad9e04c27471b450cdd/textual_dev-1.7.0.tar.gz", hash = "sha256:bf1a50eaaff4cd6a863535dd53f06dbbd62617c371604f66f56de3908220ccd5", size = 25935 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/50/4b/3c1eb9cbc39f2f28d27e10ef2fe42bfe0cf3c2f8445a454c124948d6169b/textual_dev-1.7.0-py3-none-any.whl", hash = "sha256:a93a846aeb6a06edb7808504d9c301565f7f4bf2e7046d56583ed755af356c8d", size = 27221 },
+]
+
+[[package]]
+name = "textual-imageview"
+version = "0.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "pillow" },
+    { name = "rich" },
+    { name = "textual" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4b/31/3d8a517bd8694ee0d70fd260fbc20590f00a5fcde6ca1ce2edb174c000ac/textual_imageview-0.1.1.tar.gz", hash = "sha256:4299d8ed677db0adb8fe945687470cf1421dcafd2a5dddab54b6ee8ef2ab3320", size = 3232614 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/43/56/c0514dcfdb2b67333bf4e653ca9cf0fda51004932d3b246bf835376cbaba/textual_imageview-0.1.1-py3-none-any.whl", hash = "sha256:335c8043e2f1f735b1b2ec1753a743d6762578175cd2cedae3ce67e2694800a4", size = 8875 },
+]
+
+[[package]]
+name = "textual-serve"
+version = "1.1.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "aiohttp" },
+    { name = "aiohttp-jinja2" },
+    { name = "jinja2" },
+    { name = "rich" },
+    { name = "textual" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/18/6c/57248070f525ea8a9a02d9f58dc2747c609b615b0bda1306aaeb80a233bd/textual_serve-1.1.1.tar.gz", hash = "sha256:71c662472c462e5e368defc660ee6e8eae3bfda88ca40c050c55474686eb0c54", size = 445957 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/07/a9/01d35770fde8d889e1fe28b726188cf28801e57afd369c614cd2bc100ee4/textual_serve-1.1.1-py3-none-any.whl", hash = "sha256:568782f1c0e60e3f7039d9121e1cb5c2f4ca1aaf6d6bd7aeb833d5763a534cb2", size = 445034 },
+]
+
 [[package]]
 name = "threadpoolctl"
 version = "3.5.0"
@@ -4993,6 +6890,36 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 },
 ]
 
+[[package]]
+name = "tinysegmenter"
+version = "0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/17/82/86982e4b6d16e4febc79c2a1d68ee3b707e8a020c5d2bc4af8052d0f136a/tinysegmenter-0.3.tar.gz", hash = "sha256:ed1f6d2e806a4758a73be589754384cbadadc7e1a414c81a166fc9adf2d40c6d", size = 16893 }
+
+[[package]]
+name = "tldextract"
+version = "5.1.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "filelock" },
+    { name = "idna" },
+    { name = "requests" },
+    { name = "requests-file" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/4a/4f/eee4bebcbad25a798bf55601d3a4aee52003bebcf9e55fce08b91ca541a9/tldextract-5.1.3.tar.gz", hash = "sha256:d43c7284c23f5dc8a42fd0fee2abede2ff74cc622674e4cb07f514ab3330c338", size = 125033 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c6/86/aebe15fa40a992c446be5cf14e70e58a251277494c14d26bdbcff0e658fd/tldextract-5.1.3-py3-none-any.whl", hash = "sha256:78de310cc2ca018692de5ddf320f9d6bd7c5cf857d0fd4f2175f0cdf4440ea75", size = 104923 },
+]
+
+[[package]]
+name = "tokenize-rt"
+version = "6.1.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/6b/0a/5854d8ced8c1e00193d1353d13db82d7f813f99bd5dcb776ce3e2a4c0d19/tokenize_rt-6.1.0.tar.gz", hash = "sha256:e8ee836616c0877ab7c7b54776d2fefcc3bde714449a206762425ae114b53c86", size = 5506 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/87/ba/576aac29b10dfa49a6ce650001d1bb31f81e734660555eaf144bfe5b8995/tokenize_rt-6.1.0-py2.py3-none-any.whl", hash = "sha256:d706141cdec4aa5f358945abe36b911b8cbdc844545da99e811250c0cee9b6fc", size = 6015 },
+]
+
 [[package]]
 name = "tokenizers"
 version = "0.21.0"
@@ -5047,6 +6974,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 },
 ]
 
+[[package]]
+name = "tomli-w"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/19/75/241269d1da26b624c0d5e110e8149093c759b7a286138f4efd61a60e75fe/tomli_w-1.2.0.tar.gz", hash = "sha256:2dd14fac5a47c27be9cd4c976af5a12d87fb1f0b4512f81d69cce3b35ae25021", size = 7184 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/c7/18/c86eb8e0202e32dd3df50d43d7ff9854f8e0603945ff398974c1d91ac1ef/tomli_w-1.2.0-py3-none-any.whl", hash = "sha256:188306098d013b691fcadc011abd66727d3c414c571bb01b1a174ba8c983cf90", size = 6675 },
+]
+
 [[package]]
 name = "torch"
 version = "2.5.1"
@@ -5056,21 +6992,21 @@ dependencies = [
     { name = "fsspec" },
     { name = "jinja2" },
     { name = "networkx" },
-    { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
-    { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
+    { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
     { name = "setuptools", marker = "python_full_version >= '3.12'" },
     { name = "sympy" },
-    { name = "triton", marker = "platform_machine == 'x86_64' and platform_system == 'Linux'" },
+    { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" },
     { name = "typing-extensions" },
 ]
 wheels = [
@@ -5111,7 +7047,7 @@ name = "tqdm"
 version = "4.67.1"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "colorama", marker = "platform_system == 'Windows'" },
+    { name = "colorama", marker = "sys_platform == 'win32'" },
 ]
 sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737 }
 wheels = [
@@ -5154,12 +7090,44 @@ torch = [
     { name = "torch" },
 ]
 
+[[package]]
+name = "trio"
+version = "0.28.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "attrs" },
+    { name = "cffi", marker = "(implementation_name != 'pypy' and os_name == 'nt' and platform_machine != 'aarch64' and sys_platform == 'linux') or (implementation_name != 'pypy' and os_name == 'nt' and sys_platform != 'darwin' and sys_platform != 'linux')" },
+    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+    { name = "idna" },
+    { name = "outcome" },
+    { name = "sniffio" },
+    { name = "sortedcontainers" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/b3/73/57efab729506a8d4b89814f1e356ec8f3369de0ed4fd7e7616974d09646d/trio-0.28.0.tar.gz", hash = "sha256:4e547896fe9e8a5658e54e4c7c5fa1db748cbbbaa7c965e7d40505b928c73c05", size = 580318 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/b4/04/9954a59e1fb6732f5436225c9af963811d7b24ea62a8bf96991f2cb8c26e/trio-0.28.0-py3-none-any.whl", hash = "sha256:56d58977acc1635735a96581ec70513cc781b8b6decd299c487d3be2a721cd94", size = 486317 },
+]
+
+[[package]]
+name = "trio-websocket"
+version = "0.11.1"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
+    { name = "trio" },
+    { name = "wsproto" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/dd/36/abad2385853077424a11b818d9fd8350d249d9e31d583cb9c11cd4c85eda/trio-websocket-0.11.1.tar.gz", hash = "sha256:18c11793647703c158b1f6e62de638acada927344d534e3c7628eedcb746839f", size = 26511 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/48/be/a9ae5f50cad5b6f85bd2574c2c923730098530096e170c1ce7452394d7aa/trio_websocket-0.11.1-py3-none-any.whl", hash = "sha256:520d046b0d030cf970b8b2b2e00c4c2245b3807853ecd44214acd33d74581638", size = 17408 },
+]
+
 [[package]]
 name = "triton"
 version = "3.1.0"
 source = { registry = "https://pypi.org/simple" }
 dependencies = [
-    { name = "filelock", marker = "platform_machine != 'aarch64' or sys_platform != 'linux'" },
+    { name = "filelock", marker = "(platform_machine != 'aarch64' and sys_platform == 'linux') or (sys_platform != 'darwin' and sys_platform != 'linux')" },
 ]
 wheels = [
     { url = "https://files.pythonhosted.org/packages/98/29/69aa56dc0b2eb2602b553881e34243475ea2afd9699be042316842788ff5/triton-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b0dd10a925263abbe9fa37dcde67a5e9b2383fc269fdf59f5657cac38c5d1d8", size = 209460013 },
@@ -5182,6 +7150,85 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/d0/cc/0a838ba5ca64dc832aa43f727bd586309846b0ffb2ce52422543e6075e8a/typer-0.15.1-py3-none-any.whl", hash = "sha256:7994fb7b8155b64d3402518560648446072864beefd44aa2dc36972a5972e847", size = 44908 },
 ]
 
+[[package]]
+name = "types-aiofiles"
+version = "24.1.0.20241221"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/ab/5e/f984b9ddc7eecdf31e683e692d933f3672276ed95aad6adb9aea9ecbdc29/types_aiofiles-24.1.0.20241221.tar.gz", hash = "sha256:c40f6c290b0af9e902f7f3fa91213cf5bb67f37086fb21dc0ff458253586ad55", size = 14081 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/ff/da/77902220df98ce920444cf3611fa0b1cf0dc2cfa5a137c55e93829aa458e/types_aiofiles-24.1.0.20241221-py3-none-any.whl", hash = "sha256:11d4e102af0627c02e8c1d17736caa3c39de1058bea37e2f4de6ef11a5b652ab", size = 14162 },
+]
+
+[[package]]
+name = "types-docker"
+version = "7.1.0.20241229"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "types-requests" },
+    { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/00/4b/7ca6c1fe916ef4c71f145234902bb4da074e410d9cc0bd72572790c3f06d/types_docker-7.1.0.20241229.tar.gz", hash = "sha256:d968f164bb02f934bc2f178515dd4b3c8b2b4e371a9400ec440247c09c139545", size = 29032 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/e4/32/8a1c95566816fef8f7b2407d25981cf0d3ecf2f226ed0ab3a34969994ab7/types_docker-7.1.0.20241229-py3-none-any.whl", hash = "sha256:b760745a6cb0351a19108c0b76e2a43ebc05a686f6c3ec9bc1a991ff9f1cc353", size = 43650 },
+]
+
+[[package]]
+name = "types-pillow"
+version = "10.2.0.20240822"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/18/4a/4495264dddaa600d65d68bcedb64dcccf9d9da61adff51f7d2ffd8e4c9ce/types-Pillow-10.2.0.20240822.tar.gz", hash = "sha256:559fb52a2ef991c326e4a0d20accb3bb63a7ba8d40eb493e0ecb0310ba52f0d3", size = 35389 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/66/23/e81a5354859831fcf54d488d33b80ba6133ea84f874a9c0ec40a4881e133/types_Pillow-10.2.0.20240822-py3-none-any.whl", hash = "sha256:d9dab025aba07aeb12fd50a6799d4eac52a9603488eca09d7662543983f16c5d", size = 54354 },
+]
+
+[[package]]
+name = "types-protobuf"
+version = "5.29.1.20241207"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/70/89/b661a447139f665ccea8e39bfdd52a92f803df4b5de0e6001a3537feaacb/types_protobuf-5.29.1.20241207.tar.gz", hash = "sha256:2ebcadb8ab3ef2e3e2f067e0882906d64ba0dc65fc5b0fd7a8b692315b4a0be9", size = 59190 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/7e/6e/cdf152187019d6f6d04066b23e48659d961b527e9c6d43b48459d160e332/types_protobuf-5.29.1.20241207-py3-none-any.whl", hash = "sha256:92893c42083e9b718c678badc0af7a9a1307b92afe1599e5cba5f3d35b668b2f", size = 73902 },
+]
+
+[[package]]
+name = "types-python-dateutil"
+version = "2.9.0.20241206"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/a9/60/47d92293d9bc521cd2301e423a358abfac0ad409b3a1606d8fbae1321961/types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb", size = 13802 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/0f/b3/ca41df24db5eb99b00d97f89d7674a90cb6b3134c52fb8121b6d8d30f15c/types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53", size = 14384 },
+]
+
+[[package]]
+name = "types-pytz"
+version = "2024.2.0.20241221"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/54/26/516311b02b5a215e721155fb65db8a965d061372e388d6125ebce8d674b0/types_pytz-2024.2.0.20241221.tar.gz", hash = "sha256:06d7cde9613e9f7504766a0554a270c369434b50e00975b3a4a0f6eed0f2c1a9", size = 10213 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/74/db/c92ca6920cccd9c2998b013601542e2ac5e59bc805bcff94c94ad254b7df/types_pytz-2024.2.0.20241221-py3-none-any.whl", hash = "sha256:8fc03195329c43637ed4f593663df721fef919b60a969066e22606edf0b53ad5", size = 10008 },
+]
+
+[[package]]
+name = "types-requests"
+version = "2.32.0.20241016"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "urllib3" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/fa/3c/4f2a430c01a22abd49a583b6b944173e39e7d01b688190a5618bd59a2e22/types-requests-2.32.0.20241016.tar.gz", hash = "sha256:0d9cad2f27515d0e3e3da7134a1b6f28fb97129d86b867f24d9c726452634d95", size = 18065 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/d7/01/485b3026ff90e5190b5e24f1711522e06c79f4a56c8f4b95848ac072e20f/types_requests-2.32.0.20241016-py3-none-any.whl", hash = "sha256:4195d62d6d3e043a4eaaf08ff8a62184584d2e8684e9d2aa178c7915a7da3747", size = 15836 },
+]
+
+[[package]]
+name = "types-tabulate"
+version = "0.9.0.20241207"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/3f/43/16030404a327e4ff8c692f2273854019ed36718667b2993609dc37d14dd4/types_tabulate-0.9.0.20241207.tar.gz", hash = "sha256:ac1ac174750c0a385dfd248edc6279fa328aaf4ea317915ab879a2ec47833230", size = 8195 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/5e/86/a9ebfd509cbe74471106dffed320e208c72537f9aeb0a55eaa6b1b5e4d17/types_tabulate-0.9.0.20241207-py3-none-any.whl", hash = "sha256:b8dad1343c2a8ba5861c5441370c3e35908edd234ff036d4298708a1d4cf8a85", size = 8307 },
+]
+
 [[package]]
 name = "typing-extensions"
 version = "4.12.2"
@@ -5213,6 +7260,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/a6/ab/7e5f53c3b9d14972843a647d8d7a853969a58aecc7559cb3267302c94774/tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd", size = 346586 },
 ]
 
+[[package]]
+name = "uc-micro-py"
+version = "1.0.3"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/91/7a/146a99696aee0609e3712f2b44c6274566bc368dfe8375191278045186b8/uc-micro-py-1.0.3.tar.gz", hash = "sha256:d321b92cff673ec58027c04015fcaa8bb1e005478643ff4a500882eaab88c48a", size = 6043 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/37/87/1f677586e8ac487e29672e4b17455758fce261de06a0d086167bb760361a/uc_micro_py-1.0.3-py3-none-any.whl", hash = "sha256:db1dffff340817673d7b466ec86114a9dc0e9d4d9b5ba229d9d60e5c12600cd5", size = 6229 },
+]
+
 [[package]]
 name = "umap-learn"
 version = "0.5.7"
@@ -5230,6 +7286,21 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/3c/8f/671c0e1f2572ba625cbcc1faeba9435e00330c3d6962858711445cf1e817/umap_learn-0.5.7-py3-none-any.whl", hash = "sha256:6a7e0be2facfa365a5ed6588447102bdbef32a0ef449535c25c97ea7e680073c", size = 88815 },
 ]
 
+[[package]]
+name = "uptrace"
+version = "1.27.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "opentelemetry-api" },
+    { name = "opentelemetry-exporter-otlp" },
+    { name = "opentelemetry-instrumentation" },
+    { name = "opentelemetry-sdk" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/f3/89/ba1df9328e4bd4b440ac6979e20ec8c63a26f6400598e806cc9dfef764f4/uptrace-1.27.0.tar.gz", hash = "sha256:983f783b2f4303d1d2bdfaf6ace1b7a5f072af47f78a7815f82c51fcf5099cac", size = 7633 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/77/00/054ac30e9e8312c3c79371c495dd570865eab2a05bfcd640f6242d460c8b/uptrace-1.27.0-py3-none-any.whl", hash = "sha256:d5473efa33c34e3d5738d32d19301dbf004d4e19598c658f2fa9f3f09458f630", size = 8627 },
+]
+
 [[package]]
 name = "uritemplate"
 version = "4.1.1"
@@ -5248,6 +7319,11 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 },
 ]
 
+[package.optional-dependencies]
+socks = [
+    { name = "pysocks" },
+]
+
 [[package]]
 name = "usearch"
 version = "2.16.9"
@@ -5301,6 +7377,30 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/26/59/fddd9df489fe27f492cc97626e03663fb3b9b6ef7ce8597a7cdc5f2cbbad/uvicorn-0.25.0-py3-none-any.whl", hash = "sha256:ce107f5d9bd02b4636001a77a4e74aab5e1e2b146868ebbad565237145af444c", size = 60303 },
 ]
 
+[[package]]
+name = "watchfiles"
+version = "0.20.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "anyio" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/ef/48/02d2d2cbf54e134810b2cb40ac79fdb8ce08476184536a4764717a7bc9f4/watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019", size = 37041 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/4d/db/899832e11fef2d468bf8b3c1c13289b1db4cb7c3410bb2a9612a52fc8b22/watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9", size = 417357 },
+    { url = "https://files.pythonhosted.org/packages/9f/1a/85c914e4db62a3f8197daa98a271ea380a5d200a8d3058bd9f417752bc26/watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458", size = 407258 },
+    { url = "https://files.pythonhosted.org/packages/25/ae/b7bddad421af5e33079a2ce639aa58837b715a2da98df16e25ecd310af52/watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490", size = 1331327 },
+    { url = "https://files.pythonhosted.org/packages/21/e5/b080cec4e841b1cf338ccbd958cf3232ad1691a590653b2d124b5c79cf6b/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa", size = 1301371 },
+    { url = "https://files.pythonhosted.org/packages/05/a0/2fb2c36730995a6b3f060187195dc08ad9ceee67426bdca8a4296024071c/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38", size = 1302438 },
+    { url = "https://files.pythonhosted.org/packages/13/ea/d11971958ae703cfe443b21f672169cb8bc12dbec5781b910633fa2186ec/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0", size = 1410655 },
+    { url = "https://files.pythonhosted.org/packages/6b/81/3f922f3ede53ca9c0b4095f63688ffeea19a49592d0ac62db1eb9632b1e3/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95", size = 1494222 },
+    { url = "https://files.pythonhosted.org/packages/e1/46/c9d5ee4871b187d291d62e61c41f9a4d67d4866a89704b0ad16b6949e9bd/watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf", size = 1294171 },
+    { url = "https://files.pythonhosted.org/packages/59/5e/6b64e3bf9fd4422250f3c716d992dd76dbe55e6fa1e7ebaf2bf88f389707/watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db", size = 1462256 },
+    { url = "https://files.pythonhosted.org/packages/11/c0/75f5a71ac24118ab11bd898e0114cedc72b25924ff2d960d473bddb4ec6e/watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164", size = 1461725 },
+    { url = "https://files.pythonhosted.org/packages/91/d4/0c0fdcc4293ad1b73db54896fa0de4b37439ae4f25971b5eb1708dd04f9a/watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5", size = 268193 },
+    { url = "https://files.pythonhosted.org/packages/87/79/098b1b1fcb6de16149d23283a2ab5dadce6a06b864e7a182d231f57a1f9e/watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3", size = 276723 },
+    { url = "https://files.pythonhosted.org/packages/3f/82/45dddf4f5bf8b73ba27382cebb2bb3c0ee922c7ef77d936b86276aa39dca/watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c", size = 265344 },
+]
+
 [[package]]
 name = "wcwidth"
 version = "0.2.13"
@@ -5310,6 +7410,15 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 },
 ]
 
+[[package]]
+name = "websocket-client"
+version = "1.8.0"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826 },
+]
+
 [[package]]
 name = "websockets"
 version = "14.1"
@@ -5370,6 +7479,16 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498 },
 ]
 
+[[package]]
+name = "wikipedia"
+version = "1.4.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "beautifulsoup4" },
+    { name = "requests" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/67/35/25e68fbc99e672127cc6fbb14b8ec1ba3dfef035bf1e4c90f78f24a80b7d/wikipedia-1.4.0.tar.gz", hash = "sha256:db0fad1829fdd441b1852306e9856398204dc0786d2996dd2e0c8bb8e26133b2", size = 27748 }
+
 [[package]]
 name = "win32-setctime"
 version = "1.2.0"
@@ -5421,6 +7540,18 @@ wheels = [
     { url = "https://files.pythonhosted.org/packages/2d/82/f56956041adef78f849db6b289b282e72b55ab8045a75abad81898c28d19/wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8", size = 23594 },
 ]
 
+[[package]]
+name = "wsproto"
+version = "1.2.0"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+    { name = "h11" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/c9/4a/44d3c295350d776427904d73c189e10aeae66d7f555bb2feee16d1e4ba5a/wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065", size = 53425 }
+wheels = [
+    { url = "https://files.pythonhosted.org/packages/78/58/e860788190eba3bcce367f74d29c4675466ce8dddfba85f7827588416f01/wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736", size = 24226 },
+]
+
 [[package]]
 name = "xlsxwriter"
 version = "3.2.0"

From f1d868f41c4055afc32ec9b28e0391ec44112421 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 14:30:52 -0800
Subject: [PATCH 075/110] cleanup delivery logic

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 23 +++++++------------
 1 file changed, 8 insertions(+), 15 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index c2257cbc2b08..52b7d9a3c543 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -216,15 +216,6 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
         //intentionally blocking
         var targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
-        //verify targetAgentTypes is not null
-        if (targetAgentTypes is null || targetAgentTypes.Count == 0)
-        {
-            _logger.LogWarning("No agents found registered for event {Event}.", evt);
-        }
-        else
-        {
-            await DispatchEventToAgentsAsync(targetAgentTypes, evt).ConfigureAwait(false);
-        }
         // alternate path    
         // get the event type and then send to all agents that are subscribed to that event type
         var eventType = evt.Type;
@@ -235,12 +226,10 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         if (_subscriptionsByTopic.TryGetValue(source, out var agentTypesList2)) { agentTypes.AddRange(agentTypesList2); }
         if (_subscriptionsByTopic.TryGetValue(source + "." + eventType, out var agentTypesList3)) { agentTypes.AddRange(agentTypesList3); }
         agentTypes = agentTypes.Distinct().ToList();
-        if (agentTypes.Count > 0)
-        {
-            await DispatchEventToAgentsAsync(agentTypes, evt: evt).ConfigureAwait(false);
-        }
+        targetAgentTypes.AddRange(agentTypes);
+     
         // instead of an exact match, we can also check for a prefix match where key starts with the eventType
-        else if (_subscriptionsByTopic.Keys.Any(key => key.StartsWith(eventType)))
+        if (_subscriptionsByTopic.Keys.Any(key => key.StartsWith(eventType)))
         {
             _subscriptionsByTopic.Where(
                 kvp => kvp.Key.StartsWith(eventType))
@@ -249,9 +238,13 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
                 .ToList()
                 .ForEach(async agentType =>
                 {
-                    await DispatchEventToAgentsAsync(new List<string> { agentType }, evt).ConfigureAwait(false);
+                    targetAgentTypes.Add(agentType);
                 });
         }
+        if (targetAgentTypes is not null && targetAgentTypes.Any())
+        {
+            await DispatchEventToAgentsAsync(targetAgentTypes, evt).ConfigureAwait(false);
+        }
         else
         {
             // log that no agent types were found

From 73373e0a0c168fd75677af7577fcad6a8f75977e Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Tue, 21 Jan 2025 17:38:07 -0500
Subject: [PATCH 076/110] separate grpc tests to different ports, clean up
 start() and stop()

---
 .../AgentGrpcTests.cs                         | 100 ++++++++++--------
 1 file changed, 58 insertions(+), 42 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 9a9b16669330..4d143f2e604f 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -5,7 +5,6 @@
 using System.Text.Json;
 using FluentAssertions;
 using Google.Protobuf.Reflection;
-using Microsoft.AspNetCore.Builder;
 using Microsoft.AutoGen.Contracts;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Hosting;
@@ -15,13 +14,8 @@
 
 namespace Microsoft.AutoGen.Core.Grpc.Tests;
 
-[Collection(GrpcClusterFixtureCollection.Name)]
-public class AgentGrpcTests(GrpcRuntimeFixture fixture)
+public class AgentGrpcTests
 {
-    private readonly GrpcRuntimeFixture _fixture = fixture;
-    // need a variable to store the runtime instance
-    public static WebApplication? Host { get; private set; }
-
     /// <summary>
     /// Verify that if the agent is not initialized via AgentWorker, it should throw the correct exception.
     /// </summary>
@@ -29,12 +23,12 @@ public class AgentGrpcTests(GrpcRuntimeFixture fixture)
     [Fact]
     public async Task Agent_ShouldThrowException_WhenNotInitialized()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_fixture.Client.Services);
+        using var runtime = new GrpcRuntime();
+        var (_, agent) = runtime.Start(false); // Do not initialize
+
+        // Expect an exception when calling SubscribeAsync because the agent is uninitialized
         await Assert.ThrowsAsync<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(
-            async () =>
-            {
-                await agent.SubscribeAsync("TestEvent");
-            }
+            async () => await agent.SubscribeAsync("TestEvent")
         );
     }
 
@@ -45,11 +39,12 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     [Fact]
     public async Task Agent_ShouldInitializeCorrectly()
     {
-        var (worker, agent) = _fixture.Start();
+        using var runtime = new GrpcRuntime();
+        runtime.Start();
+        var (worker, agent) = runtime.Start();
         Assert.Equal("GrpcAgentWorker", worker.GetType().Name);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
-        _fixture.Stop();
     }
     /// <summary>
     /// Test SubscribeAsync method
@@ -58,7 +53,8 @@ public async Task Agent_ShouldInitializeCorrectly()
     [Fact]
     public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
     {
-        var (_, agent) = _fixture.Start();
+        using var runtime = new GrpcRuntime();
+        var (_, agent) = runtime.Start();
         await agent.SubscribeAsync("TestEvent");
         await Task.Delay(100);
         var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
@@ -83,7 +79,6 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
             }
         }
         Assert.False(found);
-        _fixture.Stop();
     }
 
     /// <summary>
@@ -93,7 +88,8 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
     [Fact]
     public async Task StoreAsync_and_ReadAsyncTest()
     {
-        var (_, agent) = _fixture.Start();
+        using var runtime = new GrpcRuntime();
+        var (_, agent) = runtime.Start();
         Dictionary<string, string> state = new()
         {
             { "testdata", "Active" }
@@ -107,7 +103,6 @@ await agent.StoreAsync(new AgentState
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);
         Assert.Equal("Active", value);
-        _fixture.Stop();
     }
 
     /// <summary>
@@ -117,7 +112,8 @@ await agent.StoreAsync(new AgentState
     [Fact]
     public async Task PublishMessageAsync_and_ReceiveMessageTest()
     {
-        var (_, agent) = _fixture.Start();
+        using var runtime = new GrpcRuntime();
+        var (_, agent) = runtime.Start();
         await agent.SubscribeAsync("TestEvent").ConfigureAwait(true);
         var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
         var found = false;
@@ -137,7 +133,6 @@ await agent.PublishMessageAsync(new TextMessage()
         }).ConfigureAwait(true);
         await Task.Delay(10000);
         Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
-        _fixture.Stop();
     }
 
     [Fact]
@@ -192,16 +187,25 @@ public Task Handle(int item)
 /// This fixture is used to provide a runtime for the agent tests.
 /// However, it is shared between tests. So operations from one test can affect another.
 /// </remarks>
-public sealed class GrpcRuntimeFixture
+public sealed class GrpcRuntime : IDisposable
 {
-    public GrpcRuntimeFixture()
+    public IHost Client { get; private set; }
+    public IHost? AppHost { get; private set; }
+
+    public GrpcRuntime()
     {
         Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development");
-        Environment.SetEnvironmentVariable("ASPNETCORE_HTTPS_PORTS", "53071");
-        Environment.SetEnvironmentVariable("AGENT_HOST", "https://localhost:53071");
-        AppHost = StartAppHostAsync().GetAwaiter().GetResult();
-        Environment.SetEnvironmentVariable("ASPNETCORE_URLS", "https://+;http://+");
-        Client = StartClientAsync().GetAwaiter().GetResult();
+        AppHost = Host.CreateDefaultBuilder().Build();
+        Client = Host.CreateDefaultBuilder().Build();
+    }
+
+    private static int GetAvailablePort()
+    {
+        using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
+        listener.Start();
+        int port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
+        listener.Stop();
+        return port;
     }
 
     private static async Task<IHost> StartClientAsync()
@@ -213,33 +217,45 @@ private static async Task<IHost> StartAppHostAsync()
         return await Microsoft.AutoGen.Runtime.Grpc.Host.StartAsync(local: false, useGrpc: true).ConfigureAwait(false);
 
     }
-    public IHost Client { get; }
-    public IHost? AppHost { get; }
 
     /// <summary>
-    /// Start - starts the agent
+    /// Start - gets a new port and starts fresh instances
     /// </summary>
-    /// <returns>IAgentWorker, TestAgent</returns>
-    public (IAgentWorker, TestAgent) Start()
+    public (IAgentWorker, TestAgent) Start(bool initialize = true)
     {
+        int port = GetAvailablePort(); // Get a new port per test run
+
+        // Update environment variables so each test runs independently
+        Environment.SetEnvironmentVariable("ASPNETCORE_HTTPS_PORTS", port.ToString());
+        Environment.SetEnvironmentVariable("AGENT_HOST", $"https://localhost:{port}");
+
+        AppHost = StartAppHostAsync().GetAwaiter().GetResult();
+        Client = StartClientAsync().GetAwaiter().GetResult();
+
         var agent = ActivatorUtilities.CreateInstance<TestAgent>(Client.Services);
         var worker = Client.Services.GetRequiredService<IAgentWorker>();
-        Agent.Initialize(worker, agent);
+        if (initialize)
+        {
+            Agent.Initialize(worker, agent);
+        }
+
         return (worker, agent);
     }
+
     /// <summary>
-    /// Stop - stops the agent
+    /// Stop - stops the agent and ensures cleanup
     /// </summary>
-    /// <returns>void</returns>
     public void Stop()
     {
-        IHostApplicationLifetime hostApplicationLifetime = Client.Services.GetRequiredService<IHostApplicationLifetime>();
-        hostApplicationLifetime.StopApplication();
+        Client?.StopAsync().GetAwaiter().GetResult();
+        AppHost?.StopAsync().GetAwaiter().GetResult();
     }
-}
 
-[CollectionDefinition(Name)]
-public sealed class GrpcClusterFixtureCollection : ICollectionFixture<GrpcRuntimeFixture>
-{
-    public const string Name = nameof(GrpcClusterFixtureCollection);
+    /// <summary>
+    /// Dispose - Ensures cleanup after each test
+    /// </summary>
+    public void Dispose()
+    {
+        Stop();
+    }
 }

From 702cc132c005a31c4d013c17f3f519e2dd258deb Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 15:09:04 -0800
Subject: [PATCH 077/110] ensure its initialized

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs                  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 52b7d9a3c543..6ba91afbc166 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -215,7 +215,8 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
 
         var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
         //intentionally blocking
-        var targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
+        var targetAgentTypes = new List<string>();
+        targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
         // alternate path    
         // get the event type and then send to all agents that are subscribed to that event type
         var eventType = evt.Type;

From 61bf048d384fbaf20fd4a1055c2a5cd70ac34104 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 15:12:13 -0800
Subject: [PATCH 078/110] trying to avoid null

---
 .../Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 6ba91afbc166..507c3e4936cb 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -216,7 +216,7 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
         //intentionally blocking
         var targetAgentTypes = new List<string>();
-        targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
+        targetAgentTypes.AddRange(await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true));
         // alternate path    
         // get the event type and then send to all agents that are subscribed to that event type
         var eventType = evt.Type;

From 043ceeeb51de37e33f02f18f8452b00d40bf9d26 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 15:18:03 -0800
Subject: [PATCH 079/110] reducing multiple delivery

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs    | 16 +++++++++++-----
 1 file changed, 11 insertions(+), 5 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 507c3e4936cb..3e1e0d4d5912 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -216,7 +216,11 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
         //intentionally blocking
         var targetAgentTypes = new List<string>();
-        targetAgentTypes.AddRange(await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true));
+        var handlers = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
+        if (handlers is not null && handlers.Any())
+        {
+            targetAgentTypes.AddRange(handlers);
+        }
         // alternate path    
         // get the event type and then send to all agents that are subscribed to that event type
         var eventType = evt.Type;
@@ -226,9 +230,11 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         if (_subscriptionsByTopic.TryGetValue(eventType, out var agentTypesList)) { agentTypes.AddRange(agentTypesList); }
         if (_subscriptionsByTopic.TryGetValue(source, out var agentTypesList2)) { agentTypes.AddRange(agentTypesList2); }
         if (_subscriptionsByTopic.TryGetValue(source + "." + eventType, out var agentTypesList3)) { agentTypes.AddRange(agentTypesList3); }
-        agentTypes = agentTypes.Distinct().ToList();
-        targetAgentTypes.AddRange(agentTypes);
-     
+        if (agentTypes is not null && agentTypes.Any())
+        {
+            agentTypes = agentTypes.Distinct().ToList();
+            targetAgentTypes.AddRange(agentTypes);
+        }
         // instead of an exact match, we can also check for a prefix match where key starts with the eventType
         if (_subscriptionsByTopic.Keys.Any(key => key.StartsWith(eventType)))
         {
@@ -244,7 +250,7 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         }
         if (targetAgentTypes is not null && targetAgentTypes.Any())
         {
-            await DispatchEventToAgentsAsync(targetAgentTypes, evt).ConfigureAwait(false);
+            await DispatchEventToAgentsAsync(targetAgentTypes.Distinct(), evt).ConfigureAwait(false);
         }
         else
         {

From 8b65de9f14a2039e5ba7b868559ca6f2d840ac35 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 15:27:06 -0800
Subject: [PATCH 080/110] trying to reduce the number of deliveries

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs              | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 3e1e0d4d5912..01ebc265bc83 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -217,7 +217,7 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         //intentionally blocking
         var targetAgentTypes = new List<string>();
         var handlers = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
-        if (handlers is not null && handlers.Any())
+        if (handlers is not null && handlers.Count > 0)
         {
             targetAgentTypes.AddRange(handlers);
         }
@@ -230,7 +230,7 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         if (_subscriptionsByTopic.TryGetValue(eventType, out var agentTypesList)) { agentTypes.AddRange(agentTypesList); }
         if (_subscriptionsByTopic.TryGetValue(source, out var agentTypesList2)) { agentTypes.AddRange(agentTypesList2); }
         if (_subscriptionsByTopic.TryGetValue(source + "." + eventType, out var agentTypesList3)) { agentTypes.AddRange(agentTypesList3); }
-        if (agentTypes is not null && agentTypes.Any())
+        if (agentTypes is not null && agentTypes.Count > 0)
         {
             agentTypes = agentTypes.Distinct().ToList();
             targetAgentTypes.AddRange(agentTypes);
@@ -250,7 +250,8 @@ private async ValueTask DispatchEventAsync(CloudEvent evt)
         }
         if (targetAgentTypes is not null && targetAgentTypes.Any())
         {
-            await DispatchEventToAgentsAsync(targetAgentTypes.Distinct(), evt).ConfigureAwait(false);
+            targetAgentTypes = targetAgentTypes.Distinct().ToList();
+            await DispatchEventToAgentsAsync(targetAgentTypes, evt).ConfigureAwait(false);
         }
         else
         {

From 4689eccecd19b13ea77105d8015a4279377391a2 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 16:30:57 -0800
Subject: [PATCH 081/110] fix open channel test

---
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs |  4 +-
 .../GrpcGatewayServiceTests.cs                | 42 +++++++++----------
 2 files changed, 21 insertions(+), 25 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 01ebc265bc83..93468b2ddb76 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -149,9 +149,9 @@ internal async Task ConnectToWorkerProcess(IAsyncStreamReader<Message> requestSt
     {
         _logger.LogInformation("Received new connection from {Peer}.", context.Peer);
         var workerProcess = new GrpcWorkerConnection(this, requestStream, responseStream, context);
+        _workers.GetOrAdd(workerProcess, workerProcess);
+        _workersByConnection.GetOrAdd(context.Peer, workerProcess);
         await workerProcess.Connect().ConfigureAwait(false);
-        _workers[workerProcess] = workerProcess;
-        _workersByConnection[context.Peer] = workerProcess;
     }
     internal async Task SendMessageAsync(GrpcWorkerConnection connection, CloudEvent cloudEvent, CancellationToken cancellationToken = default)
     {
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 5be9404adc66..2d002f432ac6 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -31,7 +31,7 @@ public async Task Test_OpenChannel()
         using var client = new TestGrpcClient();
 
         gateway._workers.Count.Should().Be(0);
-        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
+        await OpenChannel(service, client);
         gateway._workers.Count.Should().Be(1);
     }
 
@@ -42,12 +42,9 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         using var client = new TestGrpcClient();
-
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-
-        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-
+        await OpenChannel(service: service, client);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
 
@@ -61,7 +58,6 @@ public async Task Test_Message_Exchange_Through_Gateway()
         // Simulate an agent, by publishing a new message in the request stream
         var helloEvent = new Hello { Message = $"Hello test-{client.CallContext.Peer}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
         client.AddMessage(new Message { CloudEvent = helloEvent });
-
         var helloMessageReceived = await client.ReadNext();
         helloMessageReceived!.CloudEvent.Type.Should().Be(GetFullName(typeof(Hello)));
         helloMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
@@ -74,15 +70,11 @@ public async Task Test_Message_Goes_To_Right_Worker()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         using var client = new TestGrpcClient();
-
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-
-        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-
+        await OpenChannel(service: service, client);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
-
     }
 
     [Fact]
@@ -92,12 +84,9 @@ public async Task Test_RegisterAgent_Should_Succeed()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         using var client = new TestGrpcClient();
-
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-
-        await service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
-
+        await OpenChannel(service: service, client);
         var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         response.Success.Should().BeTrue();
     }
@@ -109,10 +98,8 @@ public async Task Test_RegisterAgent_Should_Fail_For_Wrong_ConnectionId()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         using var client = new TestGrpcClient();
-
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-
         var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), "faulty_connection_id"), client.CallContext);
         response.Success.Should().BeFalse();
     }
@@ -124,9 +111,7 @@ public async Task Test_SaveState()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         var callContext = TestServerCallContext.Create();
-
-        var response = await service.SaveState(new AgentState { AgentId = new AgentId { Key = "", Type = "" } }, callContext);
-
+        var response = await service.SaveState(new AgentState { AgentId = new AgentId { Key = "Test", Type = "test" } }, callContext);
         response.Should().NotBeNull();
     }
 
@@ -137,9 +122,7 @@ public async Task Test_GetState()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         var callContext = TestServerCallContext.Create();
-
         var response = await service.GetState(new AgentId { Key = "", Type = "" }, callContext);
-
         response.Should().NotBeNull();
     }
 
@@ -152,10 +135,23 @@ private RegisterAgentTypeRequest CreateRegistrationRequest(AgentsMetadata eventT
         };
         registration.Events.AddRange(eventTypes.GetEventsForAgent(type)?.ToList());
         registration.Topics.AddRange(eventTypes.GetTopicsForAgent(type)?.ToList());
-
         return registration;
     }
 
+    private Task OpenChannel(GrpcGatewayService service, TestGrpcClient client)
+    {
+        var completion = new TaskCompletionSource<Task>();
+        var _ = Task.Run(() =>
+        {
+            completion.SetResult(
+                service.OpenChannel(
+                    client.RequestStream,
+                    client.ResponseStream,
+                    client.CallContext
+                ));
+        });
+        return completion.Task;
+    }
     private string GetFullName(Type type)
     {
         return ReflectionHelper.GetMessageDescriptor(type)!.FullName;

From ad70e5daa675171f2dc4989f72bcd198c14bf536 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 16:59:58 -0800
Subject: [PATCH 082/110] update silobuilder test cluster

---
 .../Helpers/Orleans/SiloBuilderConfigurator.cs               | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs
index fb345777a82b..bb960f7b1107 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Orleans/SiloBuilderConfigurator.cs
@@ -15,7 +15,8 @@ public void Configure(ISiloBuilder siloBuilder)
             services.AddSerializer(a => a.AddProtobufSerializer());
         });
         siloBuilder.AddMemoryStreams("StreamProvider")
-                    .AddMemoryGrainStorage("PubSubStore")
-                    .AddMemoryGrainStorage("AgentStateStore");
+            .AddMemoryGrainStorage("PubSubStore")
+            .AddMemoryGrainStorage("AgentRegistryStore")
+            .AddMemoryGrainStorage("AgentStateStore");
     }
 }

From dd1e45abcf37e6cb7e061a48712d80e807f444fa Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 17:34:11 -0800
Subject: [PATCH 083/110] cleanup open channel with cancellation

---
 .../GrpcGatewayServiceTests.cs                | 24 ++++++++-----------
 .../Helpers/Grpc/TestGrpcClient.cs            |  4 +++-
 2 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 2d002f432ac6..0a227c6862d9 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -21,18 +21,19 @@ public GrpcGatewayServiceTests(ClusterFixture fixture)
     {
         _fixture = fixture;
     }
-    // Test broadcast Event
     [Fact]
     public async Task Test_OpenChannel()
     {
         var logger = Mock.Of<ILogger<GrpcGateway>>();
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
-        using var client = new TestGrpcClient();
+        var client = new TestGrpcClient();
 
         gateway._workers.Count.Should().Be(0);
-        await OpenChannel(service, client);
+        var task = OpenChannel(service, client);
         gateway._workers.Count.Should().Be(1);
+        client.Dispose();
+        await task;
     }
 
     [Fact]
@@ -61,6 +62,8 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var helloMessageReceived = await client.ReadNext();
         helloMessageReceived!.CloudEvent.Type.Should().Be(GetFullName(typeof(Hello)));
         helloMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
+        client.Dispose();
+
     }
 
     [Fact]
@@ -89,6 +92,8 @@ public async Task Test_RegisterAgent_Should_Succeed()
         await OpenChannel(service: service, client);
         var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         response.Success.Should().BeTrue();
+        client.Dispose();
+
     }
 
     [Fact]
@@ -102,6 +107,7 @@ public async Task Test_RegisterAgent_Should_Fail_For_Wrong_ConnectionId()
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
         var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), "faulty_connection_id"), client.CallContext);
         response.Success.Should().BeFalse();
+        client.Dispose();
     }
 
     [Fact]
@@ -140,17 +146,7 @@ private RegisterAgentTypeRequest CreateRegistrationRequest(AgentsMetadata eventT
 
     private Task OpenChannel(GrpcGatewayService service, TestGrpcClient client)
     {
-        var completion = new TaskCompletionSource<Task>();
-        var _ = Task.Run(() =>
-        {
-            completion.SetResult(
-                service.OpenChannel(
-                    client.RequestStream,
-                    client.ResponseStream,
-                    client.CallContext
-                ));
-        });
-        return completion.Task;
+        return service.OpenChannel(client.RequestStream, client.ResponseStream, client.CallContext);
     }
     private string GetFullName(Type type)
     {
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
index 6795c9f9237f..e47f26eda159 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Helpers/Grpc/TestGrpcClient.cs
@@ -10,9 +10,10 @@ internal sealed class TestGrpcClient : IDisposable
     public TestServerStreamWriter<Message> ResponseStream { get; }
     public TestServerCallContext CallContext { get; }
 
+    private CancellationTokenSource CallContextCancellation = new();
     public TestGrpcClient()
     {
-        CallContext = TestServerCallContext.Create();
+        CallContext = TestServerCallContext.Create(cancellationToken: CallContextCancellation.Token);
         RequestStream = new TestAsyncStreamReader<Message>(CallContext);
         ResponseStream = new TestServerStreamWriter<Message>(CallContext);
     }
@@ -30,6 +31,7 @@ public void AddMessage(Message message)
 
     public void Dispose()
     {
+        CallContextCancellation.Cancel();
         RequestStream.Dispose();
         ResponseStream.Dispose();
     }

From cdea4209585fa58bfc530bff4ecea939f886297d Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 18:08:26 -0800
Subject: [PATCH 084/110] continue test cleanup

---
 .../GrpcGatewayServiceTests.cs                | 20 ++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 0a227c6862d9..f33ae2bf1e61 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -42,10 +42,10 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var logger = Mock.Of<ILogger<GrpcGateway>>();
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
-        using var client = new TestGrpcClient();
+        var client = new TestGrpcClient();
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-        await OpenChannel(service: service, client);
+        var task = OpenChannel(service: service, client);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
 
@@ -63,7 +63,7 @@ public async Task Test_Message_Exchange_Through_Gateway()
         helloMessageReceived!.CloudEvent.Type.Should().Be(GetFullName(typeof(Hello)));
         helloMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
         client.Dispose();
-
+        await task;
     }
 
     [Fact]
@@ -72,12 +72,14 @@ public async Task Test_Message_Goes_To_Right_Worker()
         var logger = Mock.Of<ILogger<GrpcGateway>>();
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
-        using var client = new TestGrpcClient();
+        var client = new TestGrpcClient();
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-        await OpenChannel(service: service, client);
+        var task = OpenChannel(service: service, client);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
+        client.Dispose();
+        await task;
     }
 
     [Fact]
@@ -86,14 +88,14 @@ public async Task Test_RegisterAgent_Should_Succeed()
         var logger = Mock.Of<ILogger<GrpcGateway>>();
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
-        using var client = new TestGrpcClient();
+        var client = new TestGrpcClient();
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-        await OpenChannel(service: service, client);
+        var task = OpenChannel(service: service, client);
         var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         response.Success.Should().BeTrue();
         client.Dispose();
-
+        await task;
     }
 
     [Fact]
@@ -102,7 +104,7 @@ public async Task Test_RegisterAgent_Should_Fail_For_Wrong_ConnectionId()
         var logger = Mock.Of<ILogger<GrpcGateway>>();
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
-        using var client = new TestGrpcClient();
+        var client = new TestGrpcClient();
         var assembly = typeof(PBAgent).Assembly;
         var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
         var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), "faulty_connection_id"), client.CallContext);

From 474a616cc40e082386ae896839d8f41b4925b3fe Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 19:12:43 -0800
Subject: [PATCH 085/110] remove unused

---
 dotnet/AutoGen.sln | 2 --
 1 file changed, 2 deletions(-)

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index 76a759e37692..3765c7c6f1c8 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -136,8 +136,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.AgentHost
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Runtime.Grpc.Tests", "test\Microsoft.AutoGen.Runtime.Grpc.Tests\Microsoft.AutoGen.Runtime.Grpc.Tests.csproj", "{0E7983BB-2602-421E-8B37-332E52870A10}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Tests.Shared", "test\Microsoft.AutoGen.Tests.Shared\Microsoft.AutoGen.Tests.Shared.csproj", "{14F90F79-580E-454D-BA7A-ED6D9723020D}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Tests", "test\Microsoft.AutoGen.Core.Tests\Microsoft.AutoGen.Core.Tests.csproj", "{EAFFE339-26CB-4019-991D-BCCE8E7D33A1}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.ServiceDefaults", "samples\dev-team\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj", "{599E1971-1DA9-453F-A7A8-42510BBC95C2}"

From 97f24f1991819d3541ee34cc525d95cd1348a616 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 20:27:59 -0800
Subject: [PATCH 086/110] cleaning up dispatch and impoving test reliability

---
 dotnet/AutoGen.sln                            |  1 -
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 60 ++++++-------------
 .../Services/Grpc/GrpcWorkerConnection.cs     |  3 +-
 .../Services/Orleans/RegistryGrain.cs         | 32 +++++++---
 .../AgentGrpcTests.cs                         |  4 +-
 5 files changed, 46 insertions(+), 54 deletions(-)

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index 3765c7c6f1c8..28e133c5cca5 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -438,7 +438,6 @@ Global
 		{3892C83E-7F5D-41DF-A88C-4854EAD38856} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338} = {18BF8DD7-0585-48BF-8F97-AD333080CE06}
 		{0E7983BB-2602-421E-8B37-332E52870A10} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
-		{14F90F79-580E-454D-BA7A-ED6D9723020D} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{599E1971-1DA9-453F-A7A8-42510BBC95C2} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
 		{33A28A4B-123B-4416-9631-0F759B8D6172} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 93468b2ddb76..31cc4367af1f 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -157,7 +157,7 @@ internal async Task SendMessageAsync(GrpcWorkerConnection connection, CloudEvent
     {
         await connection.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
     }
-    internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Message message)
+    internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Message message, CancellationToken cancellationToken = default)
     {
         _logger.LogInformation("Received message {Message} from connection {Connection}.", message, connection);
         switch (message.MessageCase)
@@ -169,7 +169,7 @@ internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Mess
                 DispatchResponse(connection, message.Response);
                 break;
             case Message.MessageOneofCase.CloudEvent:
-                await DispatchEventAsync(message.CloudEvent);
+                await DispatchEventAsync(message.CloudEvent, cancellationToken);
                 break;
             case Message.MessageOneofCase.RegisterAgentTypeRequest:
                 await RegisterAgentTypeAsync(connection, message.RegisterAgentTypeRequest);
@@ -210,53 +210,32 @@ private async ValueTask RegisterAgentTypeAsync(GrpcWorkerConnection connection,
         };
         await connection.ResponseStream.WriteAsync(response).ConfigureAwait(false);
     }
-    private async ValueTask DispatchEventAsync(CloudEvent evt)
+    private async ValueTask DispatchEventAsync(CloudEvent evt, CancellationToken cancellationToken = default)
     {
-
         var registry = _clusterClient.GetGrain<IRegistryGrain>(0);
         //intentionally blocking
-        var targetAgentTypes = new List<string>();
-        var handlers = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
-        if (handlers is not null && handlers.Count > 0)
-        {
-            targetAgentTypes.AddRange(handlers);
-        }
-        // alternate path    
-        // get the event type and then send to all agents that are subscribed to that event type
-        var eventType = evt.Type;
-        var source = evt.Source;
-        var agentTypes = new List<string>();
-        // ensure that we get agentTypes as an async enumerable list - try to get the value of agentTypes by topic and then cast it to an async enumerable list
-        if (_subscriptionsByTopic.TryGetValue(eventType, out var agentTypesList)) { agentTypes.AddRange(agentTypesList); }
-        if (_subscriptionsByTopic.TryGetValue(source, out var agentTypesList2)) { agentTypes.AddRange(agentTypesList2); }
-        if (_subscriptionsByTopic.TryGetValue(source + "." + eventType, out var agentTypesList3)) { agentTypes.AddRange(agentTypesList3); }
-        if (agentTypes is not null && agentTypes.Count > 0)
-        {
-            agentTypes = agentTypes.Distinct().ToList();
-            targetAgentTypes.AddRange(agentTypes);
-        }
-        // instead of an exact match, we can also check for a prefix match where key starts with the eventType
-        if (_subscriptionsByTopic.Keys.Any(key => key.StartsWith(eventType)))
-        {
-            _subscriptionsByTopic.Where(
-                kvp => kvp.Key.StartsWith(eventType))
-                .SelectMany(kvp => kvp.Value)
-                .Distinct()
-                .ToList()
-                .ForEach(async agentType =>
-                {
-                    targetAgentTypes.Add(agentType);
-                });
-        }
-        if (targetAgentTypes is not null && targetAgentTypes.Any())
+        var targetAgentTypes = await registry.GetSubscribedAndHandlingAgents(evt.Source, evt.Type).ConfigureAwait(true);
+        if (targetAgentTypes is not null && targetAgentTypes.Count > 0)
         {
             targetAgentTypes = targetAgentTypes.Distinct().ToList();
-            await DispatchEventToAgentsAsync(targetAgentTypes, evt).ConfigureAwait(false);
+            var tasks = new List<Task>(targetAgentTypes.Count);
+            foreach (var agentType in targetAgentTypes)
+            {
+                if (_supportedAgentTypes.TryGetValue(agentType, out var connections))
+                {
+                    // if the connection is alive, add it to the set, if not remove the connection from the list
+                    var activeConnections = connections.Where(c => c.Completion?.IsCompleted == false).ToList();
+                    foreach (var connection in activeConnections)
+                    {
+                        tasks.Add(this.SendMessageAsync(connection, evt, cancellationToken));
+                    }
+                }
+            }
         }
         else
         {
             // log that no agent types were found
-            _logger.LogWarning("No agent types found for event type {EventType}.", eventType);
+            _logger.LogWarning("No agent types found for event type {EventType}.", evt.Type);
         }
     }
     private async ValueTask DispatchRequestAsync(GrpcWorkerConnection connection, RpcRequest request)
@@ -403,7 +382,6 @@ public async ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionReques
             };
         }
     }
-
     public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default)
     {
         return _gatewayRegistry.GetSubscriptions(nameof(type));
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs
index 00c777953688..65046642ed01 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcWorkerConnection.cs
@@ -84,9 +84,8 @@ public async Task RunReadPump()
         {
             await foreach (var message in RequestStream.ReadAllAsync(_shutdownCancellationToken.Token))
             {
-
                 // Fire and forget
-                _gateway.OnReceivedMessageAsync(this, message).Ignore();
+                _gateway.OnReceivedMessageAsync(this, message, _shutdownCancellationToken.Token).Ignore();
             }
         }
         catch (OperationCanceledException)
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index 5dce2b5ef649..26b0d379e14c 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -21,24 +21,40 @@ public override Task OnActivateAsync(CancellationToken cancellationToken)
 
     public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, string eventType)
     {
+        List<string> agents = [];
         // get all agent types that are subscribed to the topic
         if (state.State.TopicToAgentTypesMap.TryGetValue(topic, out var subscribedAgentTypes))
         {
             // get all agent types that are handling the event
             if (state.State.EventsToAgentTypesMap.TryGetValue(eventType, out var handlingAgents))
             {
-                // return the intersection of the two sets
-                return new(subscribedAgentTypes.Intersect(handlingAgents).ToList());
-            }
-            else
-            {
-                return new();
+                agents.AddRange(subscribedAgentTypes.Intersect(handlingAgents).ToList());
             }
         }
-        else
+        if (state.State.TopicToAgentTypesMap.TryGetValue(eventType, out var eventHandlingAgents))
+        {
+            agents.AddRange(eventHandlingAgents.ToList());
+        }
+        if (state.State.TopicToAgentTypesMap.TryGetValue(topic + "." + eventType, out var combo))
+        {
+            agents.AddRange(combo.ToList());
+        }
+        // instead of an exact match, we can also check for a prefix match where key starts with the eventType
+        if (state.State.TopicToAgentTypesMap.Keys.Any(key => key.StartsWith(eventType)))
         {
-            return new();
+            state.State.TopicToAgentTypesMap.Where(
+                kvp => kvp.Key.StartsWith(eventType))
+                .SelectMany(kvp => kvp.Value)
+                .Distinct()
+                .ToList()
+                .ForEach(async agentType =>
+                {
+                    agents.Add(agentType);
+                });
         }
+        agents = agents.Distinct().ToList();
+        
+        return new ValueTask<List<string>>(agents);
     }
     public ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId)
     {
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index 4d143f2e604f..aeac2fa5b2e0 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -40,9 +40,9 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     public async Task Agent_ShouldInitializeCorrectly()
     {
         using var runtime = new GrpcRuntime();
-        runtime.Start();
         var (worker, agent) = runtime.Start();
         Assert.Equal("GrpcAgentWorker", worker.GetType().Name);
+        await Task.Delay(5000);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
     }
@@ -68,7 +68,7 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
         }
         Assert.True(found);
         await agent.UnsubscribeAsync("TestEvent").ConfigureAwait(true);
-        await Task.Delay(500);
+        await Task.Delay(1000);
         subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
         found = false;
         foreach (var subscription in subscriptions)

From 045dcbbad38119457ca0dcab7f4ac87382aaacf0 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 20:30:24 -0800
Subject: [PATCH 087/110] format

---
 .../Runtime.Grpc/Services/Orleans/RegistryGrain.cs              | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index 26b0d379e14c..775ad1c65e94 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -53,7 +53,7 @@ public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, stri
                 });
         }
         agents = agents.Distinct().ToList();
-        
+
         return new ValueTask<List<string>>(agents);
     }
     public ValueTask<(IGateway? Worker, bool NewPlacement)> GetOrPlaceAgent(AgentId agentId)

From b1cc82073f237a9b25cd95a5683c5871c320a239 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Tue, 21 Jan 2025 20:43:35 -0800
Subject: [PATCH 088/110] re-add missing project

---
 dotnet/AutoGen.sln | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index 28e133c5cca5..55cd26736573 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -142,6 +142,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.ServiceDefaults", "
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Grpc.Tests", "test\Microsoft.AutoGen.Core.Grpc.Tests\Microsoft.AutoGen.Core.Grpc.Tests.csproj", "{33A28A4B-123B-4416-9631-0F759B8D6172}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.Tests.Shared", "test\Microsoft.Autogen.Tests.Shared\Microsoft.Autogen.Tests.Shared.csproj", "{58AD8E1D-83BD-4950-A324-1A20677D78D9}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -376,6 +378,10 @@ Global
 		{33A28A4B-123B-4416-9631-0F759B8D6172}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{33A28A4B-123B-4416-9631-0F759B8D6172}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{33A28A4B-123B-4416-9631-0F759B8D6172}.Release|Any CPU.Build.0 = Release|Any CPU
+		{58AD8E1D-83BD-4950-A324-1A20677D78D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{58AD8E1D-83BD-4950-A324-1A20677D78D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{58AD8E1D-83BD-4950-A324-1A20677D78D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{58AD8E1D-83BD-4950-A324-1A20677D78D9}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -441,6 +447,7 @@ Global
 		{EAFFE339-26CB-4019-991D-BCCE8E7D33A1} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 		{599E1971-1DA9-453F-A7A8-42510BBC95C2} = {05B9C173-6441-4DCA-9AC4-E897EF75F331}
 		{33A28A4B-123B-4416-9631-0F759B8D6172} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
+		{58AD8E1D-83BD-4950-A324-1A20677D78D9} = {F823671B-3ECA-4AE6-86DA-25E920D3FE64}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {93384647-528D-46C8-922C-8DB36A382F0B}

From 47ad20518dc02bdb9f216352ce4c03035b82255d Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 22 Jan 2025 08:35:01 -0800
Subject: [PATCH 089/110] running gen-proto

---
 .../runtimes/grpc/protos/agent_worker_pb2.py  | 32 +++++-----
 .../runtimes/grpc/protos/agent_worker_pb2.pyi | 16 +++++
 .../grpc/protos/agent_worker_pb2_grpc.py      | 61 ++++++++++++++-----
 .../grpc/protos/agent_worker_pb2_grpc.pyi     | 29 +++++++--
 4 files changed, 103 insertions(+), 35 deletions(-)

diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py
index 76cd7f159b1a..24dde61576de 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.py
@@ -16,7 +16,7 @@
 from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x61gent_worker.proto\x12\x06\x61gents\x1a\x10\x63loudevent.proto\x1a\x19google/protobuf/any.proto\"\'\n\x07TopicId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0e\n\x06source\x18\x02 \x01(\t\"$\n\x07\x41gentId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\"E\n\x07Payload\x12\x11\n\tdata_type\x18\x01 \x01(\t\x12\x19\n\x11\x64\x61ta_content_type\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\x89\x02\n\nRpcRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12\x1f\n\x06target\x18\x03 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0e\n\x06method\x18\x04 \x01(\t\x12 \n\x07payload\x18\x05 \x01(\x0b\x32\x0f.agents.Payload\x12\x32\n\x08metadata\x18\x06 \x03(\x0b\x32 .agents.RpcRequest.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\xb8\x01\n\x0bRpcResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12 \n\x07payload\x18\x02 \x01(\x0b\x32\x0f.agents.Payload\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x33\n\x08metadata\x18\x04 \x03(\x0b\x32!.agents.RpcResponse.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe4\x01\n\x05\x45vent\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x14\n\x0ctopic_source\x18\x02 \x01(\t\x12$\n\x06source\x18\x03 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12 \n\x07payload\x18\x04 \x01(\x0b\x32\x0f.agents.Payload\x12-\n\x08metadata\x18\x05 \x03(\x0b\x32\x1b.agents.Event.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\\\n\x18RegisterAgentTypeRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0e\n\x06\x65vents\x18\x03 \x03(\t\x12\x0e\n\x06topics\x18\x04 \x03(\t\"^\n\x19RegisterAgentTypeResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\":\n\x10TypeSubscription\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"G\n\x16TypePrefixSubscription\x12\x19\n\x11topic_type_prefix\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"\x96\x01\n\x0cSubscription\x12\x34\n\x10typeSubscription\x18\x01 \x01(\x0b\x32\x18.agents.TypeSubscriptionH\x00\x12@\n\x16typePrefixSubscription\x18\x02 \x01(\x0b\x32\x1e.agents.TypePrefixSubscriptionH\x00\x42\x0e\n\x0csubscription\"U\n\x13SubscriptionRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12*\n\x0csubscription\x18\x02 \x01(\x0b\x32\x14.agents.Subscription\"Y\n\x14SubscriptionResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x9d\x01\n\nAgentState\x12!\n\x08\x61gent_id\x18\x01 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0c\n\x04\x65Tag\x18\x02 \x01(\t\x12\x15\n\x0b\x62inary_data\x18\x03 \x01(\x0cH\x00\x12\x13\n\ttext_data\x18\x04 \x01(\tH\x00\x12*\n\nproto_data\x18\x05 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x42\x06\n\x04\x64\x61ta\"j\n\x10GetStateResponse\x12\'\n\x0b\x61gent_state\x18\x01 \x01(\x0b\x32\x12.agents.AgentState\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"B\n\x11SaveStateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xa1\x03\n\x07Message\x12%\n\x07request\x18\x01 \x01(\x0b\x32\x12.agents.RpcRequestH\x00\x12\'\n\x08response\x18\x02 \x01(\x0b\x32\x13.agents.RpcResponseH\x00\x12\x33\n\ncloudEvent\x18\x03 \x01(\x0b\x32\x1d.io.cloudevents.v1.CloudEventH\x00\x12\x44\n\x18registerAgentTypeRequest\x18\x04 \x01(\x0b\x32 .agents.RegisterAgentTypeRequestH\x00\x12\x46\n\x19registerAgentTypeResponse\x18\x05 \x01(\x0b\x32!.agents.RegisterAgentTypeResponseH\x00\x12:\n\x13SubscriptionRequest\x18\x06 \x01(\x0b\x32\x1b.agents.SubscriptionRequestH\x00\x12<\n\x14SubscriptionResponse\x18\x07 \x01(\x0b\x32\x1c.agents.SubscriptionResponseH\x00\x42\t\n\x07message2\xa7\x03\n\x08\x41gentRpc\x12\x33\n\x0bOpenChannel\x12\x0f.agents.Message\x1a\x0f.agents.Message(\x01\x30\x01\x12\x35\n\x08GetState\x12\x0f.agents.AgentId\x1a\x18.agents.GetStateResponse\x12:\n\tSaveState\x12\x12.agents.AgentState\x1a\x19.agents.SaveStateResponse\x12T\n\rRegisterAgent\x12 .agents.RegisterAgentTypeRequest\x1a!.agents.RegisterAgentTypeResponse\x12L\n\x0f\x41\x64\x64Subscription\x12\x1b.agents.SubscriptionRequest\x1a\x1c.agents.SubscriptionResponse\x12O\n\x12RemoveSubscription\x12\x1b.agents.SubscriptionRequest\x1a\x1c.agents.SubscriptionResponseB\x1e\xaa\x02\x1bMicrosoft.AutoGen.Contractsb\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x12\x61gent_worker.proto\x12\x06\x61gents\x1a\x10\x63loudevent.proto\x1a\x19google/protobuf/any.proto\"\'\n\x07TopicId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0e\n\x06source\x18\x02 \x01(\t\"$\n\x07\x41gentId\x12\x0c\n\x04type\x18\x01 \x01(\t\x12\x0b\n\x03key\x18\x02 \x01(\t\"E\n\x07Payload\x12\x11\n\tdata_type\x18\x01 \x01(\t\x12\x19\n\x11\x64\x61ta_content_type\x18\x02 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\"\x89\x02\n\nRpcRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12$\n\x06source\x18\x02 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12\x1f\n\x06target\x18\x03 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0e\n\x06method\x18\x04 \x01(\t\x12 \n\x07payload\x18\x05 \x01(\x0b\x32\x0f.agents.Payload\x12\x32\n\x08metadata\x18\x06 \x03(\x0b\x32 .agents.RpcRequest.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\xb8\x01\n\x0bRpcResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12 \n\x07payload\x18\x02 \x01(\x0b\x32\x0f.agents.Payload\x12\r\n\x05\x65rror\x18\x03 \x01(\t\x12\x33\n\x08metadata\x18\x04 \x03(\x0b\x32!.agents.RpcResponse.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xe4\x01\n\x05\x45vent\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x14\n\x0ctopic_source\x18\x02 \x01(\t\x12$\n\x06source\x18\x03 \x01(\x0b\x32\x0f.agents.AgentIdH\x00\x88\x01\x01\x12 \n\x07payload\x18\x04 \x01(\x0b\x32\x0f.agents.Payload\x12-\n\x08metadata\x18\x05 \x03(\x0b\x32\x1b.agents.Event.MetadataEntry\x1a/\n\rMetadataEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\t\n\x07_source\"\\\n\x18RegisterAgentTypeRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0c\n\x04type\x18\x02 \x01(\t\x12\x0e\n\x06\x65vents\x18\x03 \x03(\t\x12\x0e\n\x06topics\x18\x04 \x03(\t\"^\n\x19RegisterAgentTypeResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\":\n\x10TypeSubscription\x12\x12\n\ntopic_type\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"G\n\x16TypePrefixSubscription\x12\x19\n\x11topic_type_prefix\x18\x01 \x01(\t\x12\x12\n\nagent_type\x18\x02 \x01(\t\"\x96\x01\n\x0cSubscription\x12\x34\n\x10typeSubscription\x18\x01 \x01(\x0b\x32\x18.agents.TypeSubscriptionH\x00\x12@\n\x16typePrefixSubscription\x18\x02 \x01(\x0b\x32\x1e.agents.TypePrefixSubscriptionH\x00\x42\x0e\n\x0csubscription\"?\n\x10SubscriptionList\x12+\n\rsubscriptions\x18\x01 \x03(\x0b\x32\x14.agents.Subscription\"U\n\x13SubscriptionRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12*\n\x0csubscription\x18\x02 \x01(\x0b\x32\x14.agents.Subscription\"Y\n\x14SubscriptionResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\x9d\x01\n\nAgentState\x12!\n\x08\x61gent_id\x18\x01 \x01(\x0b\x32\x0f.agents.AgentId\x12\x0c\n\x04\x65Tag\x18\x02 \x01(\t\x12\x15\n\x0b\x62inary_data\x18\x03 \x01(\x0cH\x00\x12\x13\n\ttext_data\x18\x04 \x01(\tH\x00\x12*\n\nproto_data\x18\x05 \x01(\x0b\x32\x14.google.protobuf.AnyH\x00\x42\x06\n\x04\x64\x61ta\"j\n\x10GetStateResponse\x12\'\n\x0b\x61gent_state\x18\x01 \x01(\x0b\x32\x12.agents.AgentState\x12\x0f\n\x07success\x18\x02 \x01(\x08\x12\x12\n\x05\x65rror\x18\x03 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"B\n\x11SaveStateResponse\x12\x0f\n\x07success\x18\x01 \x01(\x08\x12\x12\n\x05\x65rror\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x08\n\x06_error\"\xa1\x03\n\x07Message\x12%\n\x07request\x18\x01 \x01(\x0b\x32\x12.agents.RpcRequestH\x00\x12\'\n\x08response\x18\x02 \x01(\x0b\x32\x13.agents.RpcResponseH\x00\x12\x33\n\ncloudEvent\x18\x03 \x01(\x0b\x32\x1d.io.cloudevents.v1.CloudEventH\x00\x12\x44\n\x18registerAgentTypeRequest\x18\x04 \x01(\x0b\x32 .agents.RegisterAgentTypeRequestH\x00\x12\x46\n\x19registerAgentTypeResponse\x18\x05 \x01(\x0b\x32!.agents.RegisterAgentTypeResponseH\x00\x12:\n\x13SubscriptionRequest\x18\x06 \x01(\x0b\x32\x1b.agents.SubscriptionRequestH\x00\x12<\n\x14SubscriptionResponse\x18\x07 \x01(\x0b\x32\x1c.agents.SubscriptionResponseH\x00\x42\t\n\x07message2\xd9\x03\n\x08\x41gentRpc\x12\x33\n\x0bOpenChannel\x12\x0f.agents.Message\x1a\x0f.agents.Message(\x01\x30\x01\x12\x35\n\x08GetState\x12\x0f.agents.AgentId\x1a\x18.agents.GetStateResponse\x12:\n\tSaveState\x12\x12.agents.AgentState\x1a\x19.agents.SaveStateResponse\x12T\n\rRegisterAgent\x12 .agents.RegisterAgentTypeRequest\x1a!.agents.RegisterAgentTypeResponse\x12\x46\n\tSubscribe\x12\x1b.agents.SubscriptionRequest\x1a\x1c.agents.SubscriptionResponse\x12H\n\x0bUnsubscribe\x12\x1b.agents.SubscriptionRequest\x1a\x1c.agents.SubscriptionResponse\x12=\n\x10GetSubscriptions\x12\x0f.agents.AgentId\x1a\x18.agents.SubscriptionListB\x1e\xaa\x02\x1bMicrosoft.AutoGen.Contractsb\x06proto3')
 
 _globals = globals()
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
@@ -58,18 +58,20 @@
   _globals['_TYPEPREFIXSUBSCRIPTION']._serialized_end=1232
   _globals['_SUBSCRIPTION']._serialized_start=1235
   _globals['_SUBSCRIPTION']._serialized_end=1385
-  _globals['_SUBSCRIPTIONREQUEST']._serialized_start=1387
-  _globals['_SUBSCRIPTIONREQUEST']._serialized_end=1472
-  _globals['_SUBSCRIPTIONRESPONSE']._serialized_start=1474
-  _globals['_SUBSCRIPTIONRESPONSE']._serialized_end=1563
-  _globals['_AGENTSTATE']._serialized_start=1566
-  _globals['_AGENTSTATE']._serialized_end=1723
-  _globals['_GETSTATERESPONSE']._serialized_start=1725
-  _globals['_GETSTATERESPONSE']._serialized_end=1831
-  _globals['_SAVESTATERESPONSE']._serialized_start=1833
-  _globals['_SAVESTATERESPONSE']._serialized_end=1899
-  _globals['_MESSAGE']._serialized_start=1902
-  _globals['_MESSAGE']._serialized_end=2319
-  _globals['_AGENTRPC']._serialized_start=2322
-  _globals['_AGENTRPC']._serialized_end=2745
+  _globals['_SUBSCRIPTIONLIST']._serialized_start=1387
+  _globals['_SUBSCRIPTIONLIST']._serialized_end=1450
+  _globals['_SUBSCRIPTIONREQUEST']._serialized_start=1452
+  _globals['_SUBSCRIPTIONREQUEST']._serialized_end=1537
+  _globals['_SUBSCRIPTIONRESPONSE']._serialized_start=1539
+  _globals['_SUBSCRIPTIONRESPONSE']._serialized_end=1628
+  _globals['_AGENTSTATE']._serialized_start=1631
+  _globals['_AGENTSTATE']._serialized_end=1788
+  _globals['_GETSTATERESPONSE']._serialized_start=1790
+  _globals['_GETSTATERESPONSE']._serialized_end=1896
+  _globals['_SAVESTATERESPONSE']._serialized_start=1898
+  _globals['_SAVESTATERESPONSE']._serialized_end=1964
+  _globals['_MESSAGE']._serialized_start=1967
+  _globals['_MESSAGE']._serialized_end=2384
+  _globals['_AGENTRPC']._serialized_start=2387
+  _globals['_AGENTRPC']._serialized_end=2860
 # @@protoc_insertion_point(module_scope)
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi
index ff0ec2e9c801..899c625e53e3 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2.pyi
@@ -321,6 +321,22 @@ class Subscription(google.protobuf.message.Message):
 
 global___Subscription = Subscription
 
+@typing.final
+class SubscriptionList(google.protobuf.message.Message):
+    DESCRIPTOR: google.protobuf.descriptor.Descriptor
+
+    SUBSCRIPTIONS_FIELD_NUMBER: builtins.int
+    @property
+    def subscriptions(self) -> google.protobuf.internal.containers.RepeatedCompositeFieldContainer[global___Subscription]: ...
+    def __init__(
+        self,
+        *,
+        subscriptions: collections.abc.Iterable[global___Subscription] | None = ...,
+    ) -> None: ...
+    def ClearField(self, field_name: typing.Literal["subscriptions", b"subscriptions"]) -> None: ...
+
+global___SubscriptionList = SubscriptionList
+
 @typing.final
 class SubscriptionRequest(google.protobuf.message.Message):
     DESCRIPTOR: google.protobuf.descriptor.Descriptor
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py
index c363d9968034..d5c4a33f0e00 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.py
@@ -34,16 +34,21 @@ def __init__(self, channel):
                 request_serializer=agent__worker__pb2.RegisterAgentTypeRequest.SerializeToString,
                 response_deserializer=agent__worker__pb2.RegisterAgentTypeResponse.FromString,
                 )
-        self.AddSubscription = channel.unary_unary(
-                '/agents.AgentRpc/AddSubscription',
+        self.Subscribe = channel.unary_unary(
+                '/agents.AgentRpc/Subscribe',
                 request_serializer=agent__worker__pb2.SubscriptionRequest.SerializeToString,
                 response_deserializer=agent__worker__pb2.SubscriptionResponse.FromString,
                 )
-        self.RemoveSubscription = channel.unary_unary(
-                '/agents.AgentRpc/RemoveSubscription',
+        self.Unsubscribe = channel.unary_unary(
+                '/agents.AgentRpc/Unsubscribe',
                 request_serializer=agent__worker__pb2.SubscriptionRequest.SerializeToString,
                 response_deserializer=agent__worker__pb2.SubscriptionResponse.FromString,
                 )
+        self.GetSubscriptions = channel.unary_unary(
+                '/agents.AgentRpc/GetSubscriptions',
+                request_serializer=agent__worker__pb2.AgentId.SerializeToString,
+                response_deserializer=agent__worker__pb2.SubscriptionList.FromString,
+                )
 
 
 class AgentRpcServicer(object):
@@ -73,13 +78,19 @@ def RegisterAgent(self, request, context):
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
-    def AddSubscription(self, request, context):
+    def Subscribe(self, request, context):
+        """Missing associated documentation comment in .proto file."""
+        context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+        context.set_details('Method not implemented!')
+        raise NotImplementedError('Method not implemented!')
+
+    def Unsubscribe(self, request, context):
         """Missing associated documentation comment in .proto file."""
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')
         raise NotImplementedError('Method not implemented!')
 
-    def RemoveSubscription(self, request, context):
+    def GetSubscriptions(self, request, context):
         """Missing associated documentation comment in .proto file."""
         context.set_code(grpc.StatusCode.UNIMPLEMENTED)
         context.set_details('Method not implemented!')
@@ -108,16 +119,21 @@ def add_AgentRpcServicer_to_server(servicer, server):
                     request_deserializer=agent__worker__pb2.RegisterAgentTypeRequest.FromString,
                     response_serializer=agent__worker__pb2.RegisterAgentTypeResponse.SerializeToString,
             ),
-            'AddSubscription': grpc.unary_unary_rpc_method_handler(
-                    servicer.AddSubscription,
+            'Subscribe': grpc.unary_unary_rpc_method_handler(
+                    servicer.Subscribe,
                     request_deserializer=agent__worker__pb2.SubscriptionRequest.FromString,
                     response_serializer=agent__worker__pb2.SubscriptionResponse.SerializeToString,
             ),
-            'RemoveSubscription': grpc.unary_unary_rpc_method_handler(
-                    servicer.RemoveSubscription,
+            'Unsubscribe': grpc.unary_unary_rpc_method_handler(
+                    servicer.Unsubscribe,
                     request_deserializer=agent__worker__pb2.SubscriptionRequest.FromString,
                     response_serializer=agent__worker__pb2.SubscriptionResponse.SerializeToString,
             ),
+            'GetSubscriptions': grpc.unary_unary_rpc_method_handler(
+                    servicer.GetSubscriptions,
+                    request_deserializer=agent__worker__pb2.AgentId.FromString,
+                    response_serializer=agent__worker__pb2.SubscriptionList.SerializeToString,
+            ),
     }
     generic_handler = grpc.method_handlers_generic_handler(
             'agents.AgentRpc', rpc_method_handlers)
@@ -197,7 +213,7 @@ def RegisterAgent(request,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
     @staticmethod
-    def AddSubscription(request,
+    def Subscribe(request,
             target,
             options=(),
             channel_credentials=None,
@@ -207,14 +223,14 @@ def AddSubscription(request,
             wait_for_ready=None,
             timeout=None,
             metadata=None):
-        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/AddSubscription',
+        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/Subscribe',
             agent__worker__pb2.SubscriptionRequest.SerializeToString,
             agent__worker__pb2.SubscriptionResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
 
     @staticmethod
-    def RemoveSubscription(request,
+    def Unsubscribe(request,
             target,
             options=(),
             channel_credentials=None,
@@ -224,8 +240,25 @@ def RemoveSubscription(request,
             wait_for_ready=None,
             timeout=None,
             metadata=None):
-        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/RemoveSubscription',
+        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/Unsubscribe',
             agent__worker__pb2.SubscriptionRequest.SerializeToString,
             agent__worker__pb2.SubscriptionResponse.FromString,
             options, channel_credentials,
             insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+    @staticmethod
+    def GetSubscriptions(request,
+            target,
+            options=(),
+            channel_credentials=None,
+            call_credentials=None,
+            insecure=False,
+            compression=None,
+            wait_for_ready=None,
+            timeout=None,
+            metadata=None):
+        return grpc.experimental.unary_unary(request, target, '/agents.AgentRpc/GetSubscriptions',
+            agent__worker__pb2.AgentId.SerializeToString,
+            agent__worker__pb2.SubscriptionList.FromString,
+            options, channel_credentials,
+            insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi
index 94539461f70c..15ebf39d0d96 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/protos/agent_worker_pb2_grpc.pyi
@@ -39,16 +39,21 @@ class AgentRpcStub:
         agent_worker_pb2.RegisterAgentTypeResponse,
     ]
 
-    AddSubscription: grpc.UnaryUnaryMultiCallable[
+    Subscribe: grpc.UnaryUnaryMultiCallable[
         agent_worker_pb2.SubscriptionRequest,
         agent_worker_pb2.SubscriptionResponse,
     ]
 
-    RemoveSubscription: grpc.UnaryUnaryMultiCallable[
+    Unsubscribe: grpc.UnaryUnaryMultiCallable[
         agent_worker_pb2.SubscriptionRequest,
         agent_worker_pb2.SubscriptionResponse,
     ]
 
+    GetSubscriptions: grpc.UnaryUnaryMultiCallable[
+        agent_worker_pb2.AgentId,
+        agent_worker_pb2.SubscriptionList,
+    ]
+
 class AgentRpcAsyncStub:
     OpenChannel: grpc.aio.StreamStreamMultiCallable[
         agent_worker_pb2.Message,
@@ -70,16 +75,21 @@ class AgentRpcAsyncStub:
         agent_worker_pb2.RegisterAgentTypeResponse,
     ]
 
-    AddSubscription: grpc.aio.UnaryUnaryMultiCallable[
+    Subscribe: grpc.aio.UnaryUnaryMultiCallable[
         agent_worker_pb2.SubscriptionRequest,
         agent_worker_pb2.SubscriptionResponse,
     ]
 
-    RemoveSubscription: grpc.aio.UnaryUnaryMultiCallable[
+    Unsubscribe: grpc.aio.UnaryUnaryMultiCallable[
         agent_worker_pb2.SubscriptionRequest,
         agent_worker_pb2.SubscriptionResponse,
     ]
 
+    GetSubscriptions: grpc.aio.UnaryUnaryMultiCallable[
+        agent_worker_pb2.AgentId,
+        agent_worker_pb2.SubscriptionList,
+    ]
+
 class AgentRpcServicer(metaclass=abc.ABCMeta):
     @abc.abstractmethod
     def OpenChannel(
@@ -110,17 +120,24 @@ class AgentRpcServicer(metaclass=abc.ABCMeta):
     ) -> typing.Union[agent_worker_pb2.RegisterAgentTypeResponse, collections.abc.Awaitable[agent_worker_pb2.RegisterAgentTypeResponse]]: ...
 
     @abc.abstractmethod
-    def AddSubscription(
+    def Subscribe(
         self,
         request: agent_worker_pb2.SubscriptionRequest,
         context: _ServicerContext,
     ) -> typing.Union[agent_worker_pb2.SubscriptionResponse, collections.abc.Awaitable[agent_worker_pb2.SubscriptionResponse]]: ...
 
     @abc.abstractmethod
-    def RemoveSubscription(
+    def Unsubscribe(
         self,
         request: agent_worker_pb2.SubscriptionRequest,
         context: _ServicerContext,
     ) -> typing.Union[agent_worker_pb2.SubscriptionResponse, collections.abc.Awaitable[agent_worker_pb2.SubscriptionResponse]]: ...
 
+    @abc.abstractmethod
+    def GetSubscriptions(
+        self,
+        request: agent_worker_pb2.AgentId,
+        context: _ServicerContext,
+    ) -> typing.Union[agent_worker_pb2.SubscriptionList, collections.abc.Awaitable[agent_worker_pb2.SubscriptionList]]: ...
+
 def add_AgentRpcServicer_to_server(servicer: AgentRpcServicer, server: typing.Union[grpc.Server, grpc.aio.Server]) -> None: ...

From f5b5c2832d93a654ab0d546343ab09e6f444b3da Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 13:33:46 -0500
Subject: [PATCH 090/110] reverse build and format

---
 .github/workflows/dotnet-build.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index 67105c844801..f34e9ab68ebc 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -93,15 +93,15 @@ jobs:
       run: |
         # dotnet nuget add source --name dotnet-tool https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json --configfile NuGet.config
         dotnet restore -bl
+    - name: Build
+      run: |
+        echo "Build AutoGen"
+        dotnet build --no-restore --configuration Release -bl /p:SignAssembly=true
     - name: Format check
       run: |
         echo "Format check"
         echo "If you see any error in this step, please run 'dotnet format' locally to format the code."
         dotnet format --verify-no-changes -v diag --no-restore
-    - name: Build
-      run: |
-        echo "Build AutoGen"
-        dotnet build --no-restore --configuration Release -bl /p:SignAssembly=true
     - name: Unit Test
       run: dotnet test --no-build -bl --configuration Release --filter type=!integration
 

From 6e85aceb8b3a745de90ce3f8e71671d212711fca Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 13:39:34 -0500
Subject: [PATCH 091/110] revert

---
 .github/workflows/dotnet-build.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index f34e9ab68ebc..67105c844801 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -93,15 +93,15 @@ jobs:
       run: |
         # dotnet nuget add source --name dotnet-tool https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json --configfile NuGet.config
         dotnet restore -bl
-    - name: Build
-      run: |
-        echo "Build AutoGen"
-        dotnet build --no-restore --configuration Release -bl /p:SignAssembly=true
     - name: Format check
       run: |
         echo "Format check"
         echo "If you see any error in this step, please run 'dotnet format' locally to format the code."
         dotnet format --verify-no-changes -v diag --no-restore
+    - name: Build
+      run: |
+        echo "Build AutoGen"
+        dotnet build --no-restore --configuration Release -bl /p:SignAssembly=true
     - name: Unit Test
       run: dotnet test --no-build -bl --configuration Release --filter type=!integration
 

From 5263e3ab7fbb0b173f4f1d02dca79bc3c7bb66eb Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:04:41 -0500
Subject: [PATCH 092/110] print out restore paths

---
 .github/workflows/dotnet-build.yml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index 67105c844801..e03ce1242048 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -149,6 +149,11 @@ jobs:
       run:  dotnet --version && dotnet dev-certs https --trust
     - name: Restore dependencies
       run: |
+        ls /home/runner/work/autogen/autogen/dotnet/test/
+        ls /home/runner/work/autogen/autogen/dotnet/test/Microsoft.AutoGen.Tests.Shared
+        ls /home/runner/work/autogen/autogen/dotnet/src
+        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen
+        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen/AgentHost
         dotnet restore -bl
     - name: Build
       run: |

From a0e086b7a9b69aa90334d4a5b075ef805c07632c Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:09:31 -0500
Subject: [PATCH 093/110] print paths

---
 .github/workflows/dotnet-build.yml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index e03ce1242048..370431b0a890 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -92,6 +92,11 @@ jobs:
     - name: Restore dependencies
       run: |
         # dotnet nuget add source --name dotnet-tool https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json --configfile NuGet.config
+        ls /home/runner/work/autogen/autogen/dotnet/test/
+        ls /home/runner/work/autogen/autogen/dotnet/test/Microsoft.AutoGen.Tests.Shared
+        ls /home/runner/work/autogen/autogen/dotnet/src
+        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen
+        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen/AgentHost
         dotnet restore -bl
     - name: Format check
       run: |
@@ -149,11 +154,6 @@ jobs:
       run:  dotnet --version && dotnet dev-certs https --trust
     - name: Restore dependencies
       run: |
-        ls /home/runner/work/autogen/autogen/dotnet/test/
-        ls /home/runner/work/autogen/autogen/dotnet/test/Microsoft.AutoGen.Tests.Shared
-        ls /home/runner/work/autogen/autogen/dotnet/src
-        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen
-        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen/AgentHost
         dotnet restore -bl
     - name: Build
       run: |

From 742b44e4234f24cf530fa80cbcb24e7d26dabc61 Mon Sep 17 00:00:00 2001
From: XiaoYun Zhang <xiaoyuz@microsoft.com>
Date: Wed, 22 Jan 2025 11:11:53 -0800
Subject: [PATCH 094/110] add using in .csproj

---
 .../GrpcGatewayServiceTests.cs                                   | 1 -
 .../Microsoft.AutoGen.Runtime.Grpc.Tests.csproj                  | 1 +
 dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs    | 1 -
 3 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index f33ae2bf1e61..ce9f80e53a87 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -8,7 +8,6 @@
 using Microsoft.AutoGen.Runtime.Grpc.Tests.Helpers.Orleans;
 using Microsoft.Extensions.Logging;
 using Moq;
-using Tests.Events;
 using NewMessageReceived = Tests.Events.NewMessageReceived;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Tests;
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
index 23e3794606e1..ab0899c0f169 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/Microsoft.AutoGen.Runtime.Grpc.Tests.csproj
@@ -20,6 +20,7 @@
 
   <ItemGroup>
     <Using Include="Xunit" />
+    <Using Include="Tests.Events" />
   </ItemGroup>
 
 </Project>
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
index 655a14cb418a..1984501871a9 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/TestAgent.cs
@@ -5,7 +5,6 @@
 using Microsoft.AutoGen.Core;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
-using Tests.Events;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Tests;
 

From ab1ea0296bcb21d2d67db0c146a7136b83b09be5 Mon Sep 17 00:00:00 2001
From: XiaoYun Zhang <xiaoyuz@microsoft.com>
Date: Wed, 22 Jan 2025 11:16:30 -0800
Subject: [PATCH 095/110] fix build error

---
 .github/workflows/dotnet-build.yml | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index 370431b0a890..c21f8c76d37f 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -92,11 +92,9 @@ jobs:
     - name: Restore dependencies
       run: |
         # dotnet nuget add source --name dotnet-tool https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json --configfile NuGet.config
-        ls /home/runner/work/autogen/autogen/dotnet/test/
-        ls /home/runner/work/autogen/autogen/dotnet/test/Microsoft.AutoGen.Tests.Shared
-        ls /home/runner/work/autogen/autogen/dotnet/src
-        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen
-        ls /home/runner/work/autogen/autogen/dotnet/src/Microsoft.AutoGen/AgentHost
+
+        # ls all sub-directories under dotnet folder
+        ls -R ./dotnet
         dotnet restore -bl
     - name: Format check
       run: |

From 5676b6bf185a67e910b00154da811cd3e2c04a69 Mon Sep 17 00:00:00 2001
From: XiaoYun Zhang <xiaoyuz@microsoft.com>
Date: Wed, 22 Jan 2025 11:19:02 -0800
Subject: [PATCH 096/110] fix build error

---
 .github/workflows/dotnet-build.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index c21f8c76d37f..5491f56293dc 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -94,7 +94,7 @@ jobs:
         # dotnet nuget add source --name dotnet-tool https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json --configfile NuGet.config
 
         # ls all sub-directories under dotnet folder
-        ls -R ./dotnet
+        ls -R .
         dotnet restore -bl
     - name: Format check
       run: |

From 6df60dce716db891cf4c3ac819e7860bb907b561 Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:44:33 -0500
Subject: [PATCH 097/110] partial move

---
 dotnet/AutoGen.sln                                              | 2 +-
 .../Microsoft.Autogen.Tests.Shared.csproj2}                     | 0
 .../Protos/messages.proto                                       | 0
 3 files changed, 1 insertion(+), 1 deletion(-)
 rename dotnet/test/{Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj => Microsoft.Autogen.Tests.Shared2/Microsoft.Autogen.Tests.Shared.csproj2} (100%)
 rename dotnet/test/{Microsoft.Autogen.Tests.Shared => Microsoft.Autogen.Tests.Shared2}/Protos/messages.proto (100%)

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index 55cd26736573..e3115912a20d 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -142,7 +142,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.ServiceDefaults", "
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Core.Grpc.Tests", "test\Microsoft.AutoGen.Core.Grpc.Tests\Microsoft.AutoGen.Core.Grpc.Tests.csproj", "{33A28A4B-123B-4416-9631-0F759B8D6172}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.Tests.Shared", "test\Microsoft.Autogen.Tests.Shared\Microsoft.Autogen.Tests.Shared.csproj", "{58AD8E1D-83BD-4950-A324-1A20677D78D9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Tests.Shared", "test\Microsoft.AutoGen.Tests.Shared\Microsoft.AutoGen.Tests.Shared.csproj", "{58AD8E1D-83BD-4950-A324-1A20677D78D9}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/dotnet/test/Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj b/dotnet/test/Microsoft.Autogen.Tests.Shared2/Microsoft.Autogen.Tests.Shared.csproj2
similarity index 100%
rename from dotnet/test/Microsoft.Autogen.Tests.Shared/Microsoft.Autogen.Tests.Shared.csproj
rename to dotnet/test/Microsoft.Autogen.Tests.Shared2/Microsoft.Autogen.Tests.Shared.csproj2
diff --git a/dotnet/test/Microsoft.Autogen.Tests.Shared/Protos/messages.proto b/dotnet/test/Microsoft.Autogen.Tests.Shared2/Protos/messages.proto
similarity index 100%
rename from dotnet/test/Microsoft.Autogen.Tests.Shared/Protos/messages.proto
rename to dotnet/test/Microsoft.Autogen.Tests.Shared2/Protos/messages.proto

From 9a975aee570e0ffde17c02ec377d2f268da1418c Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:45:43 -0500
Subject: [PATCH 098/110] part 2 move

---
 .../Microsoft.AutoGen.Tests.Shared.csproj}                        | 0
 .../Protos/messages.proto                                         | 0
 2 files changed, 0 insertions(+), 0 deletions(-)
 rename dotnet/test/{Microsoft.Autogen.Tests.Shared2/Microsoft.Autogen.Tests.Shared.csproj2 => Microsoft.AutoGen.Tests.Shared/Microsoft.AutoGen.Tests.Shared.csproj} (100%)
 rename dotnet/test/{Microsoft.Autogen.Tests.Shared2 => Microsoft.AutoGen.Tests.Shared}/Protos/messages.proto (100%)

diff --git a/dotnet/test/Microsoft.Autogen.Tests.Shared2/Microsoft.Autogen.Tests.Shared.csproj2 b/dotnet/test/Microsoft.AutoGen.Tests.Shared/Microsoft.AutoGen.Tests.Shared.csproj
similarity index 100%
rename from dotnet/test/Microsoft.Autogen.Tests.Shared2/Microsoft.Autogen.Tests.Shared.csproj2
rename to dotnet/test/Microsoft.AutoGen.Tests.Shared/Microsoft.AutoGen.Tests.Shared.csproj
diff --git a/dotnet/test/Microsoft.Autogen.Tests.Shared2/Protos/messages.proto b/dotnet/test/Microsoft.AutoGen.Tests.Shared/Protos/messages.proto
similarity index 100%
rename from dotnet/test/Microsoft.Autogen.Tests.Shared2/Protos/messages.proto
rename to dotnet/test/Microsoft.AutoGen.Tests.Shared/Protos/messages.proto

From 8871b6543e89d74a8057871fa7ef304b3b57aee7 Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:51:13 -0500
Subject: [PATCH 099/110] partial move agenthost

---
 dotnet/AutoGen.sln                                              | 2 +-
 dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj         | 2 +-
 ...gen.AgentHost.csproj => Microsoft.Autogen.AgentHost.csproj2} | 0
 3 files changed, 2 insertions(+), 2 deletions(-)
 rename dotnet/src/Microsoft.AutoGen/AgentHost/{Microsoft.Autogen.AgentHost.csproj => Microsoft.Autogen.AgentHost.csproj2} (100%)

diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln
index e3115912a20d..7c747bd70cc2 100644
--- a/dotnet/AutoGen.sln
+++ b/dotnet/AutoGen.sln
@@ -132,7 +132,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Runtime.G
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Agents", "src\Microsoft.AutoGen\Agents\Microsoft.AutoGen.Agents.csproj", "{3892C83E-7F5D-41DF-A88C-4854EAD38856}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Autogen.AgentHost", "src\Microsoft.AutoGen\AgentHost\Microsoft.Autogen.AgentHost.csproj", "{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.AgentHost", "src\Microsoft.AutoGen\AgentHost\Microsoft.AutoGen.AgentHost.csproj", "{4CB42139-DEE4-40B9-AA81-1E4CCAA2F338}"
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Runtime.Grpc.Tests", "test\Microsoft.AutoGen.Runtime.Grpc.Tests\Microsoft.AutoGen.Runtime.Grpc.Tests.csproj", "{0E7983BB-2602-421E-8B37-332E52870A10}"
 EndProject
diff --git a/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj b/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj
index aa714b1b727b..275544280aba 100644
--- a/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj
+++ b/dotnet/samples/Hello/Hello.AppHost/Hello.AppHost.csproj
@@ -18,7 +18,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <ProjectReference Include="../../../src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj" />
+    <ProjectReference Include="../../../src/Microsoft.AutoGen/AgentHost/Microsoft.AutoGen.AgentHost.csproj" />
     <ProjectReference Include="..\HelloAgent\HelloAgent.csproj" />
   </ItemGroup>
 </Project>
diff --git a/dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj b/dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj2
similarity index 100%
rename from dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj
rename to dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj2

From 80b9fe2838564fa7224eab8b298067ca7d63af95 Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:51:42 -0500
Subject: [PATCH 100/110] full move agenthost

---
 ...togen.AgentHost.csproj2 => Microsoft.AutoGen.AgentHost.csproj} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename dotnet/src/Microsoft.AutoGen/AgentHost/{Microsoft.Autogen.AgentHost.csproj2 => Microsoft.AutoGen.AgentHost.csproj} (100%)

diff --git a/dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj2 b/dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.AutoGen.AgentHost.csproj
similarity index 100%
rename from dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.Autogen.AgentHost.csproj2
rename to dotnet/src/Microsoft.AutoGen/AgentHost/Microsoft.AutoGen.AgentHost.csproj

From 89988f115ebd2fa767fe5fd70970bf6c7ae7849c Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:52:56 -0500
Subject: [PATCH 101/110] revert ls in restore

---
 .github/workflows/dotnet-build.yml | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/.github/workflows/dotnet-build.yml b/.github/workflows/dotnet-build.yml
index 5491f56293dc..67105c844801 100644
--- a/.github/workflows/dotnet-build.yml
+++ b/.github/workflows/dotnet-build.yml
@@ -92,9 +92,6 @@ jobs:
     - name: Restore dependencies
       run: |
         # dotnet nuget add source --name dotnet-tool https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json --configfile NuGet.config
-
-        # ls all sub-directories under dotnet folder
-        ls -R .
         dotnet restore -bl
     - name: Format check
       run: |

From a9891c03eb743f8614d5b6cc8fe928d1108a9a12 Mon Sep 17 00:00:00 2001
From: Griffin Bassman <griffinbassman@gmail.com>
Date: Wed, 22 Jan 2025 14:59:44 -0500
Subject: [PATCH 102/110] fix case in program.cs

---
 dotnet/samples/Hello/Hello.AppHost/Program.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/samples/Hello/Hello.AppHost/Program.cs b/dotnet/samples/Hello/Hello.AppHost/Program.cs
index 31dbeb8c2db7..05cc4cae1efc 100644
--- a/dotnet/samples/Hello/Hello.AppHost/Program.cs
+++ b/dotnet/samples/Hello/Hello.AppHost/Program.cs
@@ -4,7 +4,7 @@
 using Microsoft.Extensions.Hosting;
 
 var builder = DistributedApplication.CreateBuilder(args);
-var backend = builder.AddProject<Projects.Microsoft_Autogen_AgentHost>("backend").WithExternalHttpEndpoints();
+var backend = builder.AddProject<Projects.Microsoft_AutoGen_AgentHost>("backend").WithExternalHttpEndpoints();
 var client = builder.AddProject<Projects.HelloAgent>("HelloAgentsDotNET")
     .WithReference(backend)
     .WithEnvironment("AGENT_HOST", backend.GetEndpoint("https"))

From 6ee2d09fd8468e1bef9f7e91c8559df5da3f4ba9 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 22 Jan 2025 14:53:15 -0800
Subject: [PATCH 103/110] add alternate settings so that we can debug without
 painful timeouts breaking connections

---
 .../GrpcAgentWorkerHostBuilderExtension.cs    | 27 ++++++++++++++-----
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
index c22a2b551806..91e2beacba69 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorkerHostBuilderExtension.cs
@@ -22,14 +22,27 @@ public static IHostApplicationBuilder AddGrpcAgentWorker(this IHostApplicationBu
             options.Address = new Uri(agentServiceAddress ?? builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress);
             options.ChannelOptionsActions.Add(channelOptions =>
             {
-                LoggerFactory loggerFactory = new LoggerFactory();
-                channelOptions.HttpHandler = new SocketsHttpHandler
+                var loggerFactory = new LoggerFactory();
+                if (Debugger.IsAttached)
                 {
-                    EnableMultipleHttp2Connections = true,
-                    KeepAlivePingDelay = TimeSpan.FromSeconds(20),
-                    KeepAlivePingTimeout = TimeSpan.FromSeconds(10),
-                    KeepAlivePingPolicy = HttpKeepAlivePingPolicy.Always
-                };
+                    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
                 {

From 9934896bb562b4b32b09a64c9b0f606be1a3770a Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Wed, 22 Jan 2025 15:43:57 -0800
Subject: [PATCH 104/110] update topic id so that the xlang messages flow to
 the dotnet agent in the HelloAgents sample.

---
 .../samples/core_xlang_hello_python_agent/hello_python_agent.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/python/samples/core_xlang_hello_python_agent/hello_python_agent.py b/python/samples/core_xlang_hello_python_agent/hello_python_agent.py
index 178b91de8826..07cd21fa1365 100644
--- a/python/samples/core_xlang_hello_python_agent/hello_python_agent.py
+++ b/python/samples/core_xlang_hello_python_agent/hello_python_agent.py
@@ -60,7 +60,7 @@ async def main() -> None:
 
     await runtime.publish_message(
         message=output_message,
-        topic_id=DefaultTopicId("agents.Output", "HelloAgents/python"),
+        topic_id=DefaultTopicId("agents.Output", "HelloAgents"),
         sender=AgentId("HelloAgents", "python"),
     )
     await runtime.stop_when_signal()

From edb8d047351a7ed86606cdc86d75dd10df714bf7 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 23 Jan 2025 13:16:36 -0800
Subject: [PATCH 105/110] remove WebApplication from tests.

---
 dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index 1e7b5ff10166..d796b609c4ca 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -218,7 +218,7 @@ public sealed class InMemoryAgentRuntimeFixture
 {
     public InMemoryAgentRuntimeFixture()
     {
-        var builder = WebApplication.CreateBuilder();
+        var builder = new HostApplicationBuilder();
         builder.Services.TryAddSingleton(DistributedContextPropagator.Current);
         builder.AddAgentWorker()
             .AddAgent<TestAgent>(nameof(TestAgent));

From 893489f4aba322f2b9e040447686121b768f8908 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 23 Jan 2025 14:31:13 -0800
Subject: [PATCH 106/110] merge from main

---
 protos/agent_worker.proto | 48 +++++++++++++++++++++++----------------
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index 543b3fba1321..f12943da2bc8 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -48,14 +48,12 @@ message Event {
 }
 
 message RegisterAgentTypeRequest {
-    string request_id = 1;
+    string request_id = 1; // TODO: remove once message based requests are removed
     string type = 2;
-    repeated string events = 3;
-    repeated string topics = 4;
 }
 
 message RegisterAgentTypeResponse {
-    string request_id = 1;
+    string request_id = 1; // TODO: remove once message based requests are removed
     bool success = 2;
     optional string error = 3;
 }
@@ -71,35 +69,46 @@ message TypePrefixSubscription {
 }
 
 message Subscription {
+    string id = 1;
     oneof subscription {
-        TypeSubscription typeSubscription = 1;
-        TypePrefixSubscription typePrefixSubscription = 2;
+        TypeSubscription typeSubscription = 2;
+        TypePrefixSubscription typePrefixSubscription = 3;
     }
 }
 
-message SubscriptionList {
-    repeated Subscription subscriptions = 1;
-}
-
-message SubscriptionRequest {
-    string request_id = 1;
+message AddSubscriptionRequest {
+    string request_id = 1; // TODO: remove once message based requests are removed
     Subscription subscription = 2;
 }
 
-message SubscriptionResponse {
-    string request_id = 1;
+message AddSubscriptionResponse {
+    string request_id = 1; // TODO: remove once message based requests are removed
     bool success = 2;
     optional string error = 3;
 }
 
+message RemoveSubscriptionRequest {
+    string id = 1;
+}
+
+message RemoveSubscriptionResponse {
+    bool success = 1;
+    optional string error = 2;
+}
+
+message GetSubscriptionsRequest {}
+message GetSubscriptionsResponse {
+    repeated Subscription subscriptions = 1;
+}
+
 service AgentRpc {
     rpc OpenChannel (stream Message) returns (stream Message);
     rpc GetState(AgentId) returns (GetStateResponse);
     rpc SaveState(AgentState) returns (SaveStateResponse);
     rpc RegisterAgent(RegisterAgentTypeRequest) returns (RegisterAgentTypeResponse);
-    rpc Subscribe(SubscriptionRequest) returns (SubscriptionResponse);
-    rpc Unsubscribe(SubscriptionRequest) returns (SubscriptionResponse);
-    rpc GetSubscriptions(AgentId) returns (SubscriptionList);
+    rpc AddSubscription(AddSubscriptionRequest) returns (AddSubscriptionResponse);
+    rpc RemoveSubscription(RemoveSubscriptionRequest) returns (RemoveSubscriptionResponse);
+    rpc GetSubscriptions(GetSubscriptionsRequest) returns (GetSubscriptionsResponse);
 }
 
 message AgentState {
@@ -130,8 +139,7 @@ message Message {
         io.cloudevents.v1.CloudEvent cloudEvent = 3;
         RegisterAgentTypeRequest registerAgentTypeRequest = 4;
         RegisterAgentTypeResponse registerAgentTypeResponse = 5;
-        SubscriptionRequest SubscriptionRequest = 6;
-        SubscriptionResponse SubscriptionResponse = 7;
+        AddSubscriptionRequest addSubscriptionRequest = 6;
+        AddSubscriptionResponse addSubscriptionResponse = 7;
     }
 }
-

From 7e5bee7607c55455071cb299e579a7d5bed31a11 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Thu, 23 Jan 2025 15:51:53 -0800
Subject: [PATCH 107/110] the half of the changes related to the inmemory
 runtime.

---
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    | 46 +++++++-----
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs | 71 ++++++++++++++-----
 .../Microsoft.AutoGen/Core/IAgentWorker.cs    |  6 +-
 .../Core/UninitializedAgentWorker.cs          |  5 +-
 4 files changed, 88 insertions(+), 40 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index af87ce12d644..6a7952c6f1c2 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -42,7 +42,6 @@ protected Agent(
     {
         EventTypes = eventTypes;
         AgentId = new AgentId(this.GetType().Name, Guid.NewGuid().ToString());
-        AgentId = new AgentId(this.GetType().Name, Guid.NewGuid().ToString());
         _logger = logger ?? LoggerFactory.Create(builder => { }).CreateLogger<Agent>();
         _handlersByMessageType = new(GetType().GetHandlersLookupTable());
         Worker = new UninitializedAgentWorker();
@@ -64,7 +63,7 @@ private async ValueTask AddImplicitSubscriptionsAsync()
 
         foreach (var topicType in topicTypes)
         {
-            var subscriptionRequest = new SubscriptionRequest
+            var subscriptionRequest = new AddSubscriptionRequest
             {
                 RequestId = Guid.NewGuid().ToString(),
                 Subscription = new Subscription
@@ -176,19 +175,11 @@ await this.InvokeWithActivityAsync(
     }
     public async ValueTask<List<Subscription>> GetSubscriptionsAsync()
     {
-        return await Worker.GetSubscriptionsAsync(GetType()).ConfigureAwait(false);
-    }
-    public async ValueTask<SubscriptionResponse> SubscribeAsync(string topic)
-    {
-        return await UpdateSubscriptionAsync(topic, true).ConfigureAwait(true);
-    }
-    public async ValueTask<SubscriptionResponse> UnsubscribeAsync(string topic)
-    {
-        return await UpdateSubscriptionAsync(topic, false).ConfigureAwait(true);
+        return await Worker.GetSubscriptionsAsync().ConfigureAwait(false);
     }
-    private async ValueTask<SubscriptionResponse> UpdateSubscriptionAsync(string topic, bool subscribe)
+    public async ValueTask<AddSubscriptionResponse> SubscribeAsync(string topic)
     {
-        SubscriptionRequest subscriptionRequest = new()
+        AddSubscriptionRequest subscriptionRequest = new()
         {
             RequestId = Guid.NewGuid().ToString(),
             Subscription = new Subscription
@@ -200,15 +191,38 @@ private async ValueTask<SubscriptionResponse> UpdateSubscriptionAsync(string top
                 }
             }
         };
-        var subscriptionResponse = subscribe
-            ? await Worker.SubscribeAsync(subscriptionRequest).ConfigureAwait(true)
-            : await Worker.UnsubscribeAsync(subscriptionRequest).ConfigureAwait(true);
+        var subscriptionResponse = await Worker.SubscribeAsync(subscriptionRequest).ConfigureAwait(true);
         if (!subscriptionResponse.Success)
         {
             _logger.LogError($"{GetType}{AgentId.Key}: Failed to unsubscribe from topic {topic}");
         }
         return subscriptionResponse;
     }
+    public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(Guid id)
+    {
+        RemoveSubscriptionRequest subscriptionRequest = new()
+        {
+            Id = id.ToString()
+        };
+        var subscriptionResponse = await Worker.UnsubscribeAsync(subscriptionRequest).ConfigureAwait(true);
+        if (!subscriptionResponse.Success)
+        {
+            _logger.LogError($"{GetType}{AgentId.Key}: Failed to unsubscribe from Subscription {id}");
+        }
+        return subscriptionResponse;
+    }
+    public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(string topic)
+    {
+        var subscriptions = await GetSubscriptionsAsync().ConfigureAwait(false);
+        var subscription = subscriptions.FirstOrDefault(s => s.TypeSubscription.TopicType == topic);
+        if (subscription == null)
+        {
+            var error = $"{GetType}{AgentId.Key}: Subscription not found for topic {topic}";
+            _logger.LogError(error);
+            return new RemoveSubscriptionResponse { Success = false, Error = error };
+        }
+        return await UnsubscribeAsync(subscription.Id).ConfigureAwait(true);
+    }
     public async Task StoreAsync(AgentState state, CancellationToken cancellationToken = default)
     {
         await Worker.StoreAsync(state, cancellationToken).ConfigureAwait(false);
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index aaf6c795d14d..a43b4a2d9226 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -33,6 +33,7 @@ public class AgentWorker(
     private readonly IEnumerable<Tuple<string, Type>> _configuredAgentTypes = configuredAgentTypes;
     private readonly ConcurrentDictionary<string, List<Subscription>> _subscriptionsByAgentType = new();
     private readonly ConcurrentDictionary<string, List<string>> _subscriptionsByTopic = new();
+    private readonly ConcurrentDictionary<Guid, IDictionary<string, string>> _subscriptionsByGuid = new();
     private readonly CancellationTokenSource _shutdownCancellationToken = new();
     private Task? _mailboxTask;
     private readonly object _channelLock = new();
@@ -114,10 +115,10 @@ public async Task RunMessagePump()
                             agentToInvoke.ReceiveMessage(msg);
                         }
                         break;
-                    case Message msg when msg.SubscriptionRequest != null:
-                        await SubscribeAsync(msg.SubscriptionRequest).ConfigureAwait(true);
+                    case Message msg when msg.AddSubscriptionRequest != null:
+                        await SubscribeAsync(msg.AddSubscriptionRequest).ConfigureAwait(true);
                         break;
-                    case Message msg when msg.SubscriptionResponse != null:
+                    case Message msg when msg.AddSubscriptionResponse != null:
                         break;
                     case Message msg when msg.RegisterAgentTypeResponse != null:
                         break;
@@ -134,13 +135,17 @@ public async Task RunMessagePump()
             }
         }
     }
-    public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest subscription, CancellationToken cancellationToken = default)
+    public async ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest subscription, CancellationToken cancellationToken = default)
     {
         var topic = subscription.Subscription.TypeSubscription.TopicType;
         var agentType = subscription.Subscription.TypeSubscription.AgentType;
+        var id = Guid.NewGuid();
+        subscription.Subscription.Id = id.ToString();
+        var sub = new Dictionary<string, string> { { topic, agentType } };
+        _subscriptionsByGuid.GetOrAdd(id, static _ => new Dictionary<string, string>()).Add(topic, agentType);
         _subscriptionsByAgentType.GetOrAdd(key: agentType, _ => []).Add(subscription.Subscription);
         _subscriptionsByTopic.GetOrAdd(topic, _ => []).Add(agentType);
-        var response = new SubscriptionResponse
+        var response = new AddSubscriptionResponse
         {
             RequestId = subscription.RequestId,
             Error = "",
@@ -148,33 +153,53 @@ public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest
         };
         return response;
     }
-    public async ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default)
     {
-        var topic = request.Subscription.TypeSubscription.TopicType;
-        var agentType = request.Subscription.TypeSubscription.AgentType;
-        if (_subscriptionsByAgentType.TryGetValue(agentType, out var subscriptions))
+        if (!Guid.TryParse(request.Id, out var id))
         {
-            while (subscriptions.Remove(request.Subscription))
+            var removeSubscriptionResponse = new RemoveSubscriptionResponse
             {
-                //ensures all instances are removed    
-            }
+                Error = "Invalid subscription ID",
+                Success = false
+            };
+            return removeSubscriptionResponse;
         }
-        if (_subscriptionsByTopic.TryGetValue(topic, out var agentTypes))
+        if (_subscriptionsByGuid.TryGetValue(id, out var sub))
         {
-            while (agentTypes.Remove(agentType))
+            foreach (var (topic, agentType) in sub)
             {
-                //ensures all instances are removed
+                if (_subscriptionsByTopic.TryGetValue(topic, out var innerAgentTypes))
+                {
+                    while (innerAgentTypes.Remove(agentType))
+                    {
+                        //ensures all instances are removed
+                    }
+                    _subscriptionsByTopic.AddOrUpdate(topic, innerAgentTypes, (_, _) => innerAgentTypes);
+                }
+                if (_subscriptionsByAgentType.TryGetValue(agentType, out var innerSubscriptions))
+                {
+                    foreach (var subscription in innerSubscriptions)
+                    {
+                        if (subscription.Id == id.ToString())
+                        {
+                            while (innerSubscriptions.Remove(subscription))
+                            {
+                                //ensures all instances are removed
+                            }
+                        }
+                    }
+                    _subscriptionsByAgentType.AddOrUpdate(agentType, innerSubscriptions, (_, _) => innerSubscriptions);
+                }
             }
+            _subscriptionsByGuid.TryRemove(id, out _);
         }
-        var response = new SubscriptionResponse
+        var response = new RemoveSubscriptionResponse
         {
-            RequestId = request.RequestId,
             Error = "",
             Success = true
         };
         return response;
     }
-
     public async Task StartAsync(CancellationToken cancellationToken)
     {
         StartCore();
@@ -250,7 +275,6 @@ private Agent GetOrActivateAgent(AgentId agentId)
 
         return agent;
     }
-
     public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
     {
         if (_subscriptionsByAgentType.TryGetValue(type.Name, out var subscriptions))
@@ -259,4 +283,13 @@ public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
         }
         return new ValueTask<List<Subscription>>([]);
     }
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync()
+    {
+        var subscriptions = new List<Subscription>();
+        foreach (var (_, value) in _subscriptionsByAgentType)
+        {
+            subscriptions.AddRange(value);
+        }
+        return new ValueTask<List<Subscription>>(subscriptions);
+    }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
index a8be598aa7ca..5109ecf2dcf8 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
@@ -12,7 +12,7 @@ public interface IAgentWorker
     ValueTask SendMessageAsync(Message message, CancellationToken cancellationToken = default);
     ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default);
     ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
-    ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
-    ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default);
-    ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type);
+    ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default);
+    ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default);
+    ValueTask<List<Subscription>> GetSubscriptionsAsync();
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
index fec7fef60cc5..6c7ed71f3d2d 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -15,8 +15,9 @@ public class UninitializedAgentWorker() : IAgentWorker
     public ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
-    public ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
-    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync() => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public class AgentInitalizedIncorrectlyException(string message) : Exception(message)
     {
     }

From 811d76fd0a132e81b27c66d8daeaf34c551c2ac3 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 24 Jan 2025 17:30:35 -0800
Subject: [PATCH 108/110] backing off someof the prior proto changes, updating
 the tests and methods that depended upon them,

---
 .../Core.Grpc/GrpcAgentWorker.cs              |  49 ++++-----
 dotnet/src/Microsoft.AutoGen/Core/Agent.cs    |  36 ++++--
 .../src/Microsoft.AutoGen/Core/AgentWorker.cs |   9 +-
 .../Microsoft.AutoGen/Core/IAgentWorker.cs    |   2 +-
 .../Core/UninitializedAgentWorker.cs          |   2 +-
 .../Runtime.Grpc/Abstractions/IGateway.cs     |   6 +-
 .../Runtime.Grpc/Abstractions/IRegistry.cs    |   7 +-
 .../Runtime.Grpc/Services/Grpc/GrpcGateway.cs |  49 +++------
 .../Services/Grpc/GrpcGatewayService.cs       |  11 +-
 .../Services/Orleans/AgentsRegistryState.cs   |   3 +
 .../Services/Orleans/RegistryGrain.cs         | 104 +++++++++++-------
 ....cs => AddSubscriptionRequestSurrogate.cs} |  20 ++--
 ...cs => AddSubscriptionResponseSurrogate.cs} |  20 ++--
 .../Surrogates/GetSubscriptionsRequest.cs     |  35 ++++++
 .../RegisterAgentTypeRequestSurrogate.cs      |   6 +-
 .../Surrogates/RemoveSubscriptionRequest.cs   |  35 ++++++
 .../Surrogates/RemoveSubscriptionResponse.cs  |  39 +++++++
 .../Surrogates/SubscriptionSurrogate.cs       |   5 +
 .../AgentGrpcTests.cs                         |  15 +--
 .../AgentTests.cs                             |  61 +++++-----
 .../GrpcGatewayServiceTests.cs                |  88 ++++++++++-----
 21 files changed, 393 insertions(+), 209 deletions(-)
 rename dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/{SubscriptionRequestSurrogate.cs => AddSubscriptionRequestSurrogate.cs} (51%)
 rename dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/{SubscriptionResponseSurrogate.cs => AddSubscriptionResponseSurrogate.cs} (53%)
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/GetSubscriptionsRequest.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionRequest.cs
 create mode 100644 dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionResponse.cs

diff --git a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
index 79e7c57042cd..c40ded0abb67 100644
--- a/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core.Grpc/GrpcAgentWorker.cs
@@ -81,10 +81,10 @@ private async Task RunReadPump()
                                 _logger.LogError($"Failed to register agent type '{message.RegisterAgentTypeResponse.Error}'");
                             }
                             break;
-                        case Message.MessageOneofCase.SubscriptionResponse:
-                            if (!message.SubscriptionResponse.Success)
+                        case Message.MessageOneofCase.AddSubscriptionResponse:
+                            if (!message.AddSubscriptionResponse.Success)
                             {
-                                _logger.LogError($"Failed to add subscription '{message.SubscriptionResponse.Error}'");
+                                _logger.LogError($"Failed to add subscription '{message.AddSubscriptionResponse.Error}'");
                             }
                             break;
                         case Message.MessageOneofCase.CloudEvent:
@@ -227,7 +227,7 @@ private async ValueTask RegisterAgentTypeAsync(string type, Type agentType, Canc
 
                 agents.Add(agentType);
             }
-            var topicTypes = agentType.GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
+            var topicTypes = agentType.GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic).ToList();
             /*             var response = await _client.RegisterAgentAsync(new RegisterAgentTypeRequest
                         {
                             Type = type,
@@ -240,16 +240,19 @@ await WriteChannelAsync(new Message
                 {
                     RequestId = Guid.NewGuid().ToString(),
                     Type = type,
-                    Topics = { topicTypes },
-                    Events = { events }
+                    //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
                 {
-                    SubscriptionRequest = new SubscriptionRequest
+                    AddSubscriptionRequest = new AddSubscriptionRequest
                     {
                         RequestId = Guid.NewGuid().ToString(),
                         Subscription = new Subscription
@@ -262,13 +265,12 @@ await WriteChannelAsync(new Message
                         }
                     }
                 };
-                await _client.SubscribeAsync(subscriptionRequest.SubscriptionRequest, null, null, cancellationToken);
-                //await WriteChannelAsync(subscriptionRequest, cancellationToken).ConfigureAwait(true);
+                await _client.AddSubscriptionAsync(subscriptionRequest.AddSubscriptionRequest, null, null, cancellationToken);
                 foreach (var e in events)
                 {
                     subscriptionRequest = new Message
                     {
-                        SubscriptionRequest = new SubscriptionRequest
+                        AddSubscriptionRequest = new AddSubscriptionRequest
                         {
                             RequestId = Guid.NewGuid().ToString(),
                             Subscription = new Subscription
@@ -281,8 +283,7 @@ await WriteChannelAsync(new Message
                             }
                         }
                     };
-                    await _client.SubscribeAsync(subscriptionRequest.SubscriptionRequest, null, null, cancellationToken);
-                    //await WriteChannelAsync(subscriptionRequest, cancellationToken).ConfigureAwait(true);
+                    await _client.AddSubscriptionAsync(subscriptionRequest.AddSubscriptionRequest, null, null, cancellationToken);
                 }
             }
         }
@@ -433,24 +434,20 @@ public async ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken
             throw new KeyNotFoundException($"Failed to read AgentState for {agentId}.");
         }
     }
-
-    public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
+    public async ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default)
     {
-        var agentId = new AgentId { Type = type.Name };
-        var response = _client.GetSubscriptions(agentId);
-        return new ValueTask<List<Subscription>>([.. response.Subscriptions]);
+        var response = await _client.GetSubscriptionsAsync(request, null, null, cancellationToken);
+        return response.Subscriptions.ToList();
     }
-
-    public ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    public ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default)
     {
-        var response = _client.Subscribe(request, null, null, cancellationToken);
-        return new ValueTask<SubscriptionResponse>(response);
+        var response = _client.AddSubscription(request, null, null, cancellationToken);
+        return new ValueTask<AddSubscriptionResponse>(response);
     }
-
-    public ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    public ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default)
     {
-        var response = _client.Unsubscribe(request, null, null, cancellationToken);
-        return new ValueTask<SubscriptionResponse>(response);
+        var response = _client.RemoveSubscription(request, null, null, cancellationToken);
+        return new ValueTask<RemoveSubscriptionResponse>(response);
     }
 }
 
diff --git a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
index 6a7952c6f1c2..fe6103e70c7d 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/Agent.cs
@@ -175,7 +175,8 @@ await this.InvokeWithActivityAsync(
     }
     public async ValueTask<List<Subscription>> GetSubscriptionsAsync()
     {
-        return await Worker.GetSubscriptionsAsync().ConfigureAwait(false);
+        GetSubscriptionsRequest request = new();
+        return await Worker.GetSubscriptionsAsync(request).ConfigureAwait(false);
     }
     public async ValueTask<AddSubscriptionResponse> SubscribeAsync(string topic)
     {
@@ -221,7 +222,8 @@ public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(string topic
             _logger.LogError(error);
             return new RemoveSubscriptionResponse { Success = false, Error = error };
         }
-        return await UnsubscribeAsync(subscription.Id).ConfigureAwait(true);
+        var id = Guid.Parse(subscription.Id);
+        return await UnsubscribeAsync(id).ConfigureAwait(true);
     }
     public async Task StoreAsync(AgentState state, CancellationToken cancellationToken = default)
     {
@@ -326,16 +328,32 @@ private string SetTopic(string? topic = null, string? source = null, string? key
     /// <returns>A task representing the asynchronous operation.</returns>
     public async ValueTask PublishMessageAsync<T>(T message, string topic, string source, string key, CancellationToken token = default) where T : IMessage
     {
-
-        var topicTypes = this.GetType().GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
-        if (!topicTypes.Any())
+        // if there are no topic types, use the agent's default topic subscription attribute and the agent's type and key
+        if (string.IsNullOrWhiteSpace(topic))
         {
-            topicTypes = topicTypes.Append(string.IsNullOrWhiteSpace(source) ? this.AgentId.Type + "." + this.AgentId.Key : source);
+            if (string.IsNullOrWhiteSpace(topic))
+            {
+                topic = this.AgentId.Type + "." + this.AgentId.Key;
+            }
+            else
+            {
+                topic = topic + "." + source + "." + key;
+            }
+
+            var topicTypes = this.GetType().GetCustomAttributes<TopicSubscriptionAttribute>().Select(t => t.Topic);
+            if (!topicTypes.Any())
+            {
+                topicTypes = topicTypes.Append(string.IsNullOrWhiteSpace(source) ? this.AgentId.Type + "." + this.AgentId.Key : source);
+            }
+            topicTypes = topicTypes.Append(SetTopic(topic, source, key));
+            foreach (var t in topicTypes)
+            {
+                await PublishEventAsync(t, message, token).ConfigureAwait(false);
+            }
         }
-        topicTypes = topicTypes.Append(SetTopic(topic, source, key));
-        foreach (var t in topicTypes)
+        else
         {
-            await PublishEventAsync(t, message, token).ConfigureAwait(false);
+            await PublishEventAsync(topic, message, token).ConfigureAwait(false);
         }
     }
     public async ValueTask PublishMessageAsync<T>(T message, string topic, string source, CancellationToken token = default) where T : IMessage
diff --git a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
index a43b4a2d9226..b2d94d2475b5 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/AgentWorker.cs
@@ -176,18 +176,17 @@ public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscr
                     }
                     _subscriptionsByTopic.AddOrUpdate(topic, innerAgentTypes, (_, _) => innerAgentTypes);
                 }
+                var toRemove = new List<Subscription>();
                 if (_subscriptionsByAgentType.TryGetValue(agentType, out var innerSubscriptions))
                 {
                     foreach (var subscription in innerSubscriptions)
                     {
                         if (subscription.Id == id.ToString())
                         {
-                            while (innerSubscriptions.Remove(subscription))
-                            {
-                                //ensures all instances are removed
-                            }
+                            toRemove.Add(subscription);
                         }
                     }
+                    foreach (var subscription in toRemove) { innerSubscriptions.Remove(subscription); }
                     _subscriptionsByAgentType.AddOrUpdate(agentType, innerSubscriptions, (_, _) => innerSubscriptions);
                 }
             }
@@ -283,7 +282,7 @@ public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type)
         }
         return new ValueTask<List<Subscription>>([]);
     }
-    public ValueTask<List<Subscription>> GetSubscriptionsAsync()
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default)
     {
         var subscriptions = new List<Subscription>();
         foreach (var (_, value) in _subscriptionsByAgentType)
diff --git a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
index 5109ecf2dcf8..f3e8bc7308ec 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/IAgentWorker.cs
@@ -14,5 +14,5 @@ public interface IAgentWorker
     ValueTask<AgentState> ReadAsync(AgentId agentId, CancellationToken cancellationToken = default);
     ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default);
     ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default);
-    ValueTask<List<Subscription>> GetSubscriptionsAsync();
+    ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
index 6c7ed71f3d2d..4aa14ac22ce3 100644
--- a/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
+++ b/dotnet/src/Microsoft.AutoGen/Core/UninitializedAgentWorker.cs
@@ -15,7 +15,7 @@ public class UninitializedAgentWorker() : IAgentWorker
     public ValueTask SendResponseAsync(RpcResponse response, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask StoreAsync(AgentState value, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
-    public ValueTask<List<Subscription>> GetSubscriptionsAsync() => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default) => throw new AgentInitalizedIncorrectlyException(AgentNotInitializedMessage);
     public class AgentInitalizedIncorrectlyException(string message) : Exception(message)
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
index 02aeb6bf0c3f..33bb94f7c49b 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IGateway.cs
@@ -11,8 +11,8 @@ public interface IGateway : IGrainObserver
     ValueTask StoreAsync(Contracts.AgentState value);
     ValueTask<Contracts.AgentState> ReadAsync(AgentId agentId);
     ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(RegisterAgentTypeRequest request);
-    ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request);
-    ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request);
-    ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type);
+    ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request);
+    ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request);
+    ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request);
     Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
index 08007dd4ad62..436fa038774e 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Abstractions/IRegistry.cs
@@ -67,19 +67,18 @@ public interface IRegistry
     /// </summary>
     /// <param name="request">The subscription request.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    ValueTask SubscribeAsync(SubscriptionRequest request);
+    ValueTask SubscribeAsync(AddSubscriptionRequest request);
 
     /// <summary>
     /// Unsubscribes an agent from a topic.
     /// </summary>
     /// <param name="request">The unsubscription request.</param>
     /// <returns>A task representing the asynchronous operation.</returns>
-    ValueTask UnsubscribeAsync(SubscriptionRequest request); // TODO: This should have its own request type.
+    ValueTask UnsubscribeAsync(RemoveSubscriptionRequest request); // TODO: This should have its own request type.
 
     /// <summary>
     /// Gets the subscriptions for a specified agent type.
     /// </summary>
-    /// <param name="agentType">The type of the agent.</param>
     /// <returns>A task representing the asynchronous operation, with the subscriptions as the result.</returns>
-    ValueTask<List<Subscription>> GetSubscriptions(string agentType);
+    ValueTask<List<Subscription>> GetSubscriptions(GetSubscriptionsRequest request);
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 31cc4367af1f..913b7b5bbeb4 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -101,12 +101,12 @@ public async ValueTask<RegisterAgentTypeResponse> RegisterAgentTypeAsync(Registe
             };
         }
     }
-    public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    public async ValueTask<AddSubscriptionResponse> SubscribeAsync(AddSubscriptionRequest request, CancellationToken cancellationToken = default)
     {
         try
         {
             await _gatewayRegistry.SubscribeAsync(request).ConfigureAwait(true);
-            return new SubscriptionResponse
+            return new AddSubscriptionResponse
             {
                 Success = true,
                 RequestId = request.RequestId
@@ -114,7 +114,7 @@ public async ValueTask<SubscriptionResponse> SubscribeAsync(SubscriptionRequest
         }
         catch (Exception ex)
         {
-            return new SubscriptionResponse
+            return new AddSubscriptionResponse
             {
                 Success = false,
                 RequestId = request.RequestId,
@@ -174,8 +174,8 @@ internal async Task OnReceivedMessageAsync(GrpcWorkerConnection connection, Mess
             case Message.MessageOneofCase.RegisterAgentTypeRequest:
                 await RegisterAgentTypeAsync(connection, message.RegisterAgentTypeRequest);
                 break;
-            case Message.MessageOneofCase.SubscriptionRequest:
-                await AddSubscriptionAsync(connection, message.SubscriptionRequest);
+            case Message.MessageOneofCase.AddSubscriptionRequest:
+                await AddSubscriptionAsync(connection, message.AddSubscriptionRequest);
                 break;
             default:
                 // if it wasn't recognized return bad request
@@ -297,7 +297,7 @@ private static async ValueTask RespondBadRequestAsync(GrpcWorkerConnection conne
     {
         throw new RpcException(new Status(StatusCode.InvalidArgument, error));
     }
-    private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, SubscriptionRequest request)
+    private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, AddSubscriptionRequest request)
     {
         var topic = "";
         var agentType = "";
@@ -317,7 +317,7 @@ private async ValueTask AddSubscriptionAsync(GrpcWorkerConnection connection, Su
         //var response = new SubscriptionResponse { RequestId = request.RequestId, Error = "", Success = true };
         Message response = new()
         {
-            SubscriptionResponse = new()
+            AddSubscriptionResponse = new()
             {
                 RequestId = request.RequestId,
                 Error = "",
@@ -361,73 +361,60 @@ public async Task SendMessageAsync(IConnection connection, CloudEvent cloudEvent
         await queue.ResponseStream.WriteAsync(new Message { CloudEvent = cloudEvent }, cancellationToken).ConfigureAwait(false);
     }
 
-    public async ValueTask<SubscriptionResponse> UnsubscribeAsync(SubscriptionRequest request, CancellationToken cancellationToken = default)
+    public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscriptionRequest request, CancellationToken cancellationToken = default)
     {
         try
         {
             await _gatewayRegistry.UnsubscribeAsync(request).ConfigureAwait(true);
-            return new SubscriptionResponse
+            return new RemoveSubscriptionResponse
+
             {
                 Success = true,
-                RequestId = request.RequestId
             };
         }
         catch (Exception ex)
         {
-            return new SubscriptionResponse
+            return new RemoveSubscriptionResponse
             {
                 Success = false,
-                RequestId = request.RequestId,
                 Error = ex.Message
             };
         }
-    }
-    public ValueTask<List<Subscription>> GetSubscriptionsAsync(Type type, CancellationToken cancellationToken = default)
+    } 
+    public ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default)
     {
-        return _gatewayRegistry.GetSubscriptions(nameof(type));
+        return _gatewayRegistry.GetSubscriptions(request);
     }
-    public ValueTask<List<Subscription>> GetSubscriptionsAsync(string type, CancellationToken cancellationToken = default)
-    {
-        return _gatewayRegistry.GetSubscriptions(type);
-    }
-
     async ValueTask<RpcResponse> IGateway.InvokeRequestAsync(RpcRequest request)
     {
         return await InvokeRequestAsync(request, default).ConfigureAwait(false);
     }
-
     async ValueTask IGateway.BroadcastEventAsync(CloudEvent evt)
     {
         await BroadcastEventAsync(evt, default).ConfigureAwait(false);
     }
-
     ValueTask IGateway.StoreAsync(AgentState value)
     {
         return StoreAsync(value, default);
     }
-
     ValueTask<AgentState> IGateway.ReadAsync(AgentId agentId)
     {
         return ReadAsync(agentId, default);
     }
-
     ValueTask<RegisterAgentTypeResponse> IGateway.RegisterAgentTypeAsync(RegisterAgentTypeRequest request)
     {
         return RegisterAgentTypeAsync(request, default);
     }
-
-    ValueTask<SubscriptionResponse> IGateway.SubscribeAsync(SubscriptionRequest request)
+    ValueTask<AddSubscriptionResponse> IGateway.SubscribeAsync(AddSubscriptionRequest request)
     {
         return SubscribeAsync(request, default);
     }
-
-    ValueTask<SubscriptionResponse> IGateway.UnsubscribeAsync(SubscriptionRequest request)
+    ValueTask<RemoveSubscriptionResponse> IGateway.UnsubscribeAsync(RemoveSubscriptionRequest request)
     {
         return UnsubscribeAsync(request, default);
     }
-
-    ValueTask<List<Subscription>> IGateway.GetSubscriptionsAsync(Type type)
+    ValueTask<List<Subscription>> IGateway.GetSubscriptionsAsync(GetSubscriptionsRequest request)
     {
-        return GetSubscriptionsAsync(type, default);
+        return GetSubscriptionsAsync(request);
     }
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
index 5c33e90e164e..9481922943c9 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGatewayService.cs
@@ -39,20 +39,19 @@ public override async Task<SaveStateResponse> SaveState(AgentState request, Serv
             Success = true // TODO: Implement error handling
         };
     }
-    public override async Task<SubscriptionResponse> Subscribe(SubscriptionRequest request, ServerCallContext context)
+    public override async Task<AddSubscriptionResponse> AddSubscription(AddSubscriptionRequest request, ServerCallContext context)
     {
         request.RequestId = context.Peer;
         return await Gateway.SubscribeAsync(request).ConfigureAwait(true);
     }
-    public override async Task<SubscriptionResponse> Unsubscribe(SubscriptionRequest request, ServerCallContext context)
+    public override async Task<RemoveSubscriptionResponse> RemoveSubscription(RemoveSubscriptionRequest request, ServerCallContext context)
     {
-        request.RequestId = context.Peer;
         return await Gateway.UnsubscribeAsync(request).ConfigureAwait(true);
     }
-    public override async Task<SubscriptionList> GetSubscriptions(AgentId request, ServerCallContext context)
+    public override async Task<GetSubscriptionsResponse> GetSubscriptions(GetSubscriptionsRequest request, ServerCallContext context)
     {
-        var subscriptions = await Gateway.GetSubscriptionsAsync(request.Type);
-        return new SubscriptionList { Subscriptions = { subscriptions } };
+        var subscriptions = await Gateway.GetSubscriptionsAsync(request);
+        return new GetSubscriptionsResponse { Subscriptions = { subscriptions } };
     }
     public override async Task<RegisterAgentTypeResponse> RegisterAgent(RegisterAgentTypeRequest request, ServerCallContext context)
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
index 3e69bd3cc3a9..8be5e8dd5873 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/AgentsRegistryState.cs
@@ -1,6 +1,8 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
 // AgentsRegistryState.cs
 
+using Microsoft.AutoGen.Contracts;
+
 namespace Microsoft.AutoGen.Runtime.Grpc;
 
 public class AgentsRegistryState
@@ -9,4 +11,5 @@ public class AgentsRegistryState
     public Dictionary<string, HashSet<string>> AgentsToTopicsMap { get; set; } = [];
     public Dictionary<string, HashSet<string>> TopicToAgentTypesMap { get; set; } = [];
     public Dictionary<string, HashSet<string>> EventsToAgentTypesMap { get; set; } = [];
+    public Dictionary<string, HashSet<Subscription>> GuidSubscriptionsMap { get; set; } = [];
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
index 775ad1c65e94..4129a0bc413b 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/RegistryGrain.cs
@@ -25,11 +25,12 @@ public ValueTask<List<string>> GetSubscribedAndHandlingAgents(string topic, stri
         // get all agent types that are subscribed to the topic
         if (state.State.TopicToAgentTypesMap.TryGetValue(topic, out var subscribedAgentTypes))
         {
-            // get all agent types that are handling the event
+            /*// get all agent types that are handling the event
             if (state.State.EventsToAgentTypesMap.TryGetValue(eventType, out var handlingAgents))
             {
                 agents.AddRange(subscribedAgentTypes.Intersect(handlingAgents).ToList());
-            }
+            }*/
+            agents.AddRange(subscribedAgentTypes.ToList());
         }
         if (state.State.TopicToAgentTypesMap.TryGetValue(eventType, out var eventHandlingAgents))
         {
@@ -96,20 +97,21 @@ public ValueTask RemoveWorker(IGateway worker)
         }
         return ValueTask.CompletedTask;
     }
-    public async ValueTask RegisterAgentType(RegisterAgentTypeRequest registration, IGateway worker)
+    public async ValueTask RegisterAgentType(RegisterAgentTypeRequest registration, IGateway gateway)
     {
         if (!_supportedAgentTypes.TryGetValue(registration.Type, out var supportedAgentTypes))
         {
             supportedAgentTypes = _supportedAgentTypes[registration.Type] = [];
         }
 
-        if (!supportedAgentTypes.Contains(worker))
+        if (!supportedAgentTypes.Contains(gateway))
         {
-            supportedAgentTypes.Add(worker);
+            supportedAgentTypes.Add(gateway);
         }
 
-        var workerState = GetOrAddWorker(worker);
+        var workerState = GetOrAddWorker(gateway);
         workerState.SupportedTypes.Add(registration.Type);
+        /* future
         state.State.AgentsToEventsMap[registration.Type] = new HashSet<string>(registration.Events);
         state.State.AgentsToTopicsMap[registration.Type] = new HashSet<string>(registration.Topics);
 
@@ -136,6 +138,7 @@ public async ValueTask RegisterAgentType(RegisterAgentTypeRequest registration,
 
             eventSet.Add(registration.Type);
         }
+        */
         await state.WriteStateAsync().ConfigureAwait(false);
     }
     public ValueTask AddWorker(IGateway worker)
@@ -200,9 +203,11 @@ private WorkerState GetOrAddWorker(IGateway worker)
         return null;
     }
 
-    public async ValueTask SubscribeAsync(SubscriptionRequest sub)
+    public async ValueTask SubscribeAsync(AddSubscriptionRequest subscription)
     {
-        switch (sub.Subscription.SubscriptionCase)
+        var guid = Guid.NewGuid().ToString();
+        subscription.Subscription.Id = guid;
+        switch (subscription.Subscription.SubscriptionCase)
         {
             //TODO: this doesnt look right
             case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
@@ -210,22 +215,31 @@ public async ValueTask SubscribeAsync(SubscriptionRequest sub)
             case Subscription.SubscriptionOneofCase.TypeSubscription:
                 {
                     // add the topic to the set of topics for the agent type
-                    state.State.AgentsToTopicsMap.TryGetValue(sub.Subscription.TypeSubscription.AgentType, out var topics);
+                    state.State.AgentsToTopicsMap.TryGetValue(subscription.Subscription.TypeSubscription.AgentType, out var topics);
                     if (topics is null)
                     {
                         topics = new HashSet<string>();
-                        state.State.AgentsToTopicsMap[sub.Subscription.TypeSubscription.AgentType] = topics;
+                        state.State.AgentsToTopicsMap[subscription.Subscription.TypeSubscription.AgentType] = topics;
                     }
-                    topics.Add(sub.Subscription.TypeSubscription.TopicType);
+                    topics.Add(subscription.Subscription.TypeSubscription.TopicType);
 
                     // add the agent type to the set of agent types for the topic
-                    state.State.TopicToAgentTypesMap.TryGetValue(sub.Subscription.TypeSubscription.TopicType, out var agents);
+                    state.State.TopicToAgentTypesMap.TryGetValue(subscription.Subscription.TypeSubscription.TopicType, out var agents);
                     if (agents is null)
                     {
                         agents = new HashSet<string>();
-                        state.State.TopicToAgentTypesMap[sub.Subscription.TypeSubscription.TopicType] = agents;
+                        state.State.TopicToAgentTypesMap[subscription.Subscription.TypeSubscription.TopicType] = agents;
+                    }
+                    agents.Add(subscription.Subscription.TypeSubscription.AgentType);
+
+                    // add the subscription by Guid
+                    state.State.GuidSubscriptionsMap.TryGetValue(guid, out var existingSubscriptions);
+                    if (existingSubscriptions is null)
+                    {
+                        existingSubscriptions = new HashSet<Subscription>();
+                        state.State.GuidSubscriptionsMap[guid] = existingSubscriptions;
                     }
-                    agents.Add(sub.Subscription.TypeSubscription.AgentType);
+                    existingSubscriptions.Add(subscription.Subscription);
                     break;
                 }
             default:
@@ -233,37 +247,42 @@ public async ValueTask SubscribeAsync(SubscriptionRequest sub)
         }
         await state.WriteStateAsync().ConfigureAwait(false);
     }
-    public async ValueTask UnsubscribeAsync(SubscriptionRequest request)
+    public async ValueTask UnsubscribeAsync(RemoveSubscriptionRequest request)
     {
-        switch (request.Subscription.SubscriptionCase)
+        var guid = request.Id;
+        // does the guid parse?
+        if (!Guid.TryParse(guid, out var _))
         {
-            case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
-                break;
-            case Subscription.SubscriptionOneofCase.TypeSubscription:
+            throw new InvalidOperationException("Invalid subscription id");
+        }
+        if (state.State.GuidSubscriptionsMap.TryGetValue(guid, out var subscriptions))
+        {
+            foreach (var subscription in subscriptions)
+            {
+                switch (subscription.SubscriptionCase)
                 {
-                    // remove the topic from the set of topics for the agent type
-                    state.State.AgentsToTopicsMap.TryGetValue(request.Subscription.TypeSubscription.AgentType, out var topics);
-                    if (topics is not null)
-                    {
-                        while (topics.Remove(request.Subscription.TypeSubscription.TopicType))
+                    case Subscription.SubscriptionOneofCase.TypeSubscription:
                         {
-                            // ensures all instances are removed
-                        }
-                    }
+                            // remove the topic from the set of topics for the agent type
+                            state.State.AgentsToTopicsMap.TryGetValue(subscription.TypeSubscription.AgentType, out var topics);
+                            topics?.Remove(subscription.TypeSubscription.TopicType);
 
-                    // remove the agent type from the set of agent types for the topic
-                    state.State.TopicToAgentTypesMap.TryGetValue(request.Subscription.TypeSubscription.TopicType, out var agents);
-                    if (agents is not null)
-                    {
-                        while (agents.Remove(request.Subscription.TypeSubscription.AgentType))
-                        {
-                            // ensures all instances are removed
+                            // remove the agent type from the set of agent types for the topic
+                            state.State.TopicToAgentTypesMap.TryGetValue(subscription.TypeSubscription.TopicType, out var agents);
+                            agents?.Remove(subscription.TypeSubscription.AgentType);
+
+                            //remove the subscription by Guid
+                            state.State.GuidSubscriptionsMap.TryGetValue(guid, out var existingSubscriptions);
+                            existingSubscriptions?.Remove(subscription);
+                            break;
                         }
-                    }
-                    break;
+                    case Subscription.SubscriptionOneofCase.TypePrefixSubscription:
+                        break;
+                    default:
+                        throw new InvalidOperationException("Invalid subscription type");
                 }
-            default:
-                throw new InvalidOperationException("Invalid subscription type");
+            }
+            state.State.GuidSubscriptionsMap.Remove(guid);
         }
         await state.WriteStateAsync().ConfigureAwait(false);
     }
@@ -287,6 +306,15 @@ public ValueTask<List<Subscription>> GetSubscriptions(string agentType)
         }
         return new(subscriptions);
     }
+    public ValueTask<List<Subscription>> GetSubscriptions(GetSubscriptionsRequest request)
+    {
+        var subscriptions = new List<Subscription>();
+        foreach (var kvp in state.State.GuidSubscriptionsMap)
+        {
+            subscriptions.AddRange(kvp.Value);
+        }
+        return new(subscriptions);
+    }
 
     private sealed class WorkerState
     {
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionRequestSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
similarity index 51%
rename from dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionRequestSurrogate.cs
rename to dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
index f273b0b2347c..e732c3ffc982 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionRequestSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionRequestSurrogate.cs
@@ -1,12 +1,12 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
-// SubscriptionRequestSurrogate.cs
+// AddSubscriptionRequestSurrogate.cs
 
 using Microsoft.AutoGen.Contracts;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
 
 [GenerateSerializer]
-public struct SubscriptionRequestSurrogate
+public struct AddSubscriptionRequestSurrogate
 {
     [Id(0)]
     public string RequestId;
@@ -15,13 +15,13 @@ public struct SubscriptionRequestSurrogate
 }
 
 [RegisterConverter]
-public sealed class SubscriptionRequestSurrogateConverter :
-    IConverter<SubscriptionRequest, SubscriptionRequestSurrogate>
+public sealed class AddSubscriptionRequestSurrogateConverter :
+    IConverter<AddSubscriptionRequest, AddSubscriptionRequestSurrogate>
 {
-    public SubscriptionRequest ConvertFromSurrogate(
-        in SubscriptionRequestSurrogate surrogate)
+    public AddSubscriptionRequest ConvertFromSurrogate(
+        in AddSubscriptionRequestSurrogate surrogate)
     {
-        var request = new SubscriptionRequest()
+        var request = new AddSubscriptionRequest()
         {
             RequestId = surrogate.RequestId,
             Subscription = surrogate.Subscription
@@ -29,9 +29,9 @@ public SubscriptionRequest ConvertFromSurrogate(
         return request;
     }
 
-    public SubscriptionRequestSurrogate ConvertToSurrogate(
-        in SubscriptionRequest value) =>
-        new SubscriptionRequestSurrogate
+    public AddSubscriptionRequestSurrogate ConvertToSurrogate(
+        in AddSubscriptionRequest value) =>
+        new AddSubscriptionRequestSurrogate
         {
             RequestId = value.RequestId,
             Subscription = value.Subscription
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionResponseSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
similarity index 53%
rename from dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionResponseSurrogate.cs
rename to dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
index 5e8938643dcc..d35a3c5f6f89 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionResponseSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/AddSubscriptionResponseSurrogate.cs
@@ -1,12 +1,12 @@
 // Copyright (c) Microsoft Corporation. All rights reserved.
-// SubscriptionResponseSurrogate.cs
+// AddSubscriptionResponseSurrogate.cs
 
 using Microsoft.AutoGen.Contracts;
 
 namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
 
 [GenerateSerializer]
-public struct SubscriptionResponseSurrogate
+public struct AddSubscriptionResponseSurrogate
 {
     [Id(0)]
     public string RequestId;
@@ -17,21 +17,21 @@ public struct SubscriptionResponseSurrogate
 }
 
 [RegisterConverter]
-public sealed class SubscriptionResponseSurrogateConverter :
-    IConverter<SubscriptionResponse, SubscriptionResponseSurrogate>
+public sealed class AddSubscriptionResponseSurrogateConverter :
+    IConverter<AddSubscriptionResponse, AddSubscriptionResponseSurrogate>
 {
-    public SubscriptionResponse ConvertFromSurrogate(
-        in SubscriptionResponseSurrogate surrogate) =>
-        new SubscriptionResponse
+    public AddSubscriptionResponse ConvertFromSurrogate(
+        in AddSubscriptionResponseSurrogate surrogate) =>
+        new AddSubscriptionResponse
         {
             RequestId = surrogate.RequestId,
             Success = surrogate.Success,
             Error = surrogate.Error
         };
 
-    public SubscriptionResponseSurrogate ConvertToSurrogate(
-        in SubscriptionResponse value) =>
-        new SubscriptionResponseSurrogate
+    public AddSubscriptionResponseSurrogate ConvertToSurrogate(
+        in AddSubscriptionResponse value) =>
+        new AddSubscriptionResponseSurrogate
         {
             RequestId = value.RequestId,
             Success = value.Success,
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/GetSubscriptionsRequest.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/GetSubscriptionsRequest.cs
new file mode 100644
index 000000000000..ef06ef2260ca
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/GetSubscriptionsRequest.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// GetSubscriptionsRequest.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct GetSubscriptionsRequestSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public Subscription Subscription;
+}
+
+[RegisterConverter]
+public sealed class GetSubscriptionsRequestSurrogateConverter :
+    IConverter<GetSubscriptionsRequest, GetSubscriptionsRequestSurrogate>
+{
+    public GetSubscriptionsRequest ConvertFromSurrogate(
+        in GetSubscriptionsRequestSurrogate surrogate)
+    {
+        var request = new GetSubscriptionsRequest()
+        {
+        };
+        return request;
+    }
+
+    public GetSubscriptionsRequestSurrogate ConvertToSurrogate(
+        in GetSubscriptionsRequest value) =>
+        new GetSubscriptionsRequestSurrogate
+        {
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs
index 5d8b6fd25a03..a4bc2347bc95 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RegisterAgentTypeRequestSurrogate.cs
@@ -31,8 +31,9 @@ public RegisterAgentTypeRequest ConvertFromSurrogate(
             RequestId = surrogate.RequestId,
             Type = surrogate.Type
         };
+        /* future
         request.Events.Add(surrogate.Events);
-        request.Topics.Add(surrogate.Topics);
+        request.Topics.Add(surrogate.Topics);*/
         return request;
     }
 
@@ -42,7 +43,8 @@ public RegisterAgentTypeRequestSurrogate ConvertToSurrogate(
         {
             RequestId = value.RequestId,
             Type = value.Type,
+            /* future
             Events = value.Events,
-            Topics = value.Topics
+            Topics = value.Topics */
         };
 }
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionRequest.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionRequest.cs
new file mode 100644
index 000000000000..73c0844d5871
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionRequest.cs
@@ -0,0 +1,35 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// RemoveSubscriptionRequest.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct RemoveSubscriptionRequestSurrogate
+{
+    [Id(0)]
+    public string Id;
+}
+
+[RegisterConverter]
+public sealed class RemoveSubscriptionRequestConverter :
+    IConverter<RemoveSubscriptionRequest, RemoveSubscriptionRequestSurrogate>
+{
+    public RemoveSubscriptionRequest ConvertFromSurrogate(
+        in RemoveSubscriptionRequestSurrogate surrogate)
+    {
+        var request = new RemoveSubscriptionRequest()
+        {
+            Id = surrogate.Id
+        };
+        return request;
+    }
+
+    public RemoveSubscriptionRequestSurrogate ConvertToSurrogate(
+        in RemoveSubscriptionRequest value) =>
+        new RemoveSubscriptionRequestSurrogate
+        {
+            Id = value.Id
+        };
+}
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionResponse.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionResponse.cs
new file mode 100644
index 000000000000..da006b8f54dd
--- /dev/null
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/RemoveSubscriptionResponse.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// RemoveSubscriptionResponse.cs
+
+using Microsoft.AutoGen.Contracts;
+
+namespace Microsoft.AutoGen.Runtime.Grpc.Orleans.Surrogates;
+
+[GenerateSerializer]
+public struct RemoveSubscriptionResponseSurrogate
+{
+    [Id(0)]
+    public string RequestId;
+    [Id(1)]
+    public bool Success;
+    [Id(2)]
+    public string Error;
+}
+
+[RegisterConverter]
+public sealed class SubscriptionResponseSurrogateConverter :
+    IConverter<RemoveSubscriptionResponse, RemoveSubscriptionResponseSurrogate>
+{
+    public RemoveSubscriptionResponse ConvertFromSurrogate(
+        in RemoveSubscriptionResponseSurrogate surrogate) =>
+        new RemoveSubscriptionResponse
+        {
+            Success = surrogate.Success,
+            Error = surrogate.Error
+        };
+
+    public RemoveSubscriptionResponseSurrogate ConvertToSurrogate(
+        in RemoveSubscriptionResponse value) =>
+        new RemoveSubscriptionResponseSurrogate
+        {
+            Success = value.Success,
+            Error = value.Error
+        };
+}
+
diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs
index abf18143929d..1fd56c176278 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Orleans/Surrogates/SubscriptionSurrogate.cs
@@ -12,6 +12,8 @@ public struct SubscriptionSurrogate
     public TypeSubscription? TypeSubscription;
     [Id(1)]
     public TypePrefixSubscription? TypePrefixSubscription;
+    [Id(2)]
+    public string Id;
 }
 
 [RegisterConverter]
@@ -25,6 +27,7 @@ public Subscription ConvertFromSurrogate(
         {
             return new Subscription
             {
+                Id = surrogate.Id,
                 TypeSubscription = surrogate.TypeSubscription
             };
         }
@@ -32,6 +35,7 @@ public Subscription ConvertFromSurrogate(
         {
             return new Subscription
             {
+                Id = surrogate.Id,
                 TypePrefixSubscription = surrogate.TypePrefixSubscription
             };
         }
@@ -42,6 +46,7 @@ public SubscriptionSurrogate ConvertToSurrogate(
     {
         return new SubscriptionSurrogate
         {
+            Id = value.Id,
             TypeSubscription = value.TypeSubscription,
             TypePrefixSubscription = value.TypePrefixSubscription
         };
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
index aeac2fa5b2e0..3594abad842d 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Grpc.Tests/AgentGrpcTests.cs
@@ -114,25 +114,26 @@ public async Task PublishMessageAsync_and_ReceiveMessageTest()
     {
         using var runtime = new GrpcRuntime();
         var (_, agent) = runtime.Start();
-        await agent.SubscribeAsync("TestEvent").ConfigureAwait(true);
+        var topicType = "TestTopic";
+        await agent.SubscribeAsync(topicType).ConfigureAwait(true);
         var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
         var found = false;
         foreach (var subscription in subscriptions)
         {
-            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            if (subscription.TypeSubscription.TopicType == topicType)
             {
                 found = true;
             }
         }
         Assert.True(found);
-
         await agent.PublishMessageAsync(new TextMessage()
         {
-            Source = "TestEvent",
+            Source = topicType,
             TextMessage_ = "buffer"
-        }).ConfigureAwait(true);
-        await Task.Delay(10000);
-        Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
+        }, topicType).ConfigureAwait(true);
+        await Task.Delay(100);
+        Assert.True(TestAgent.ReceivedMessages.ContainsKey(topicType));
+        runtime.Stop();
     }
 
     [Fact]
diff --git a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
index d796b609c4ca..aa0cf91d981f 100644
--- a/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Core.Tests/AgentTests.cs
@@ -6,7 +6,6 @@
 using System.Text.Json;
 using FluentAssertions;
 using Google.Protobuf.Reflection;
-using Microsoft.AspNetCore.Builder;
 using Microsoft.AutoGen.Contracts;
 using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -18,13 +17,8 @@
 namespace Microsoft.AutoGen.Core.Tests;
 
 [Collection(ClusterFixtureCollection.Name)]
-public class AgentTests(InMemoryAgentRuntimeFixture fixture)
+public class AgentTests()
 {
-    private readonly IServiceProvider _serviceProvider = fixture.AppHost.Services;
-    private readonly InMemoryAgentRuntimeFixture _fixture = fixture;
-    // need a variable to store the runtime instance
-    public static WebApplication? Host { get; private set; }
-
     /// <summary>
     /// Verify that if the agent is not initialized via AgentWorker, it should throw the correct exception.
     /// </summary>
@@ -32,7 +26,8 @@ public class AgentTests(InMemoryAgentRuntimeFixture fixture)
     [Fact]
     public async Task Agent_ShouldThrowException_WhenNotInitialized()
     {
-        var agent = ActivatorUtilities.CreateInstance<TestAgent>(_serviceProvider);
+        using var runtime = new InMemoryAgentRuntimeFixture();
+        var agent = ActivatorUtilities.CreateInstance<TestAgent>(runtime.AppHost.Services);
         await Assert.ThrowsAsync<UninitializedAgentWorker.AgentInitalizedIncorrectlyException>(
             async () =>
             {
@@ -48,11 +43,12 @@ public async Task Agent_ShouldThrowException_WhenNotInitialized()
     [Fact]
     public async Task Agent_ShouldInitializeCorrectly()
     {
-        var (worker, agent) = _fixture.Start();
+        var runtime = new InMemoryAgentRuntimeFixture();
+        var (worker, agent) = runtime.Start();
         Assert.Equal("AgentWorker", worker.GetType().Name);
         var subscriptions = await agent.GetSubscriptionsAsync();
         Assert.Equal(2, subscriptions.Count);
-        _fixture.Stop();
+        runtime.Stop();
     }
     /// <summary>
     /// Test SubscribeAsync method
@@ -61,7 +57,8 @@ public async Task Agent_ShouldInitializeCorrectly()
     [Fact]
     public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
     {
-        var (_, agent) = _fixture.Start();
+        var runtime = new InMemoryAgentRuntimeFixture();
+        var (_, agent) = runtime.Start();
         await agent.SubscribeAsync("TestEvent");
         await Task.Delay(100);
         var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
@@ -86,7 +83,7 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
             }
         }
         Assert.False(found);
-        _fixture.Stop();
+        runtime.Stop();
     }
 
     /// <summary>
@@ -96,7 +93,8 @@ public async Task SubscribeAsync_UnsubscribeAsync_and_GetSubscriptionsTest()
     [Fact]
     public async Task StoreAsync_and_ReadAsyncTest()
     {
-        var (_, agent) = _fixture.Start();
+        var runtime = new InMemoryAgentRuntimeFixture();
+        var (_, agent) = runtime.Start();
         Dictionary<string, string> state = new()
         {
             { "testdata", "Active" }
@@ -110,7 +108,7 @@ await agent.StoreAsync(new AgentState
         var read = JsonSerializer.Deserialize<Dictionary<string, string>>(readState.TextData) ?? new Dictionary<string, string> { { "data", "No state data found" } };
         read.TryGetValue("testdata", out var value);
         Assert.Equal("Active", value);
-        _fixture.Stop();
+        runtime.Stop();
     }
 
     /// <summary>
@@ -120,13 +118,15 @@ await agent.StoreAsync(new AgentState
     [Fact]
     public async Task PublishMessageAsync_and_ReceiveMessageTest()
     {
-        var (_, agent) = _fixture.Start();
-        await agent.SubscribeAsync("TestEvent").ConfigureAwait(true);
+        var runtime = new InMemoryAgentRuntimeFixture();
+        var (_, agent) = runtime.Start();
+        var topicType = "TestTopic";
+        await agent.SubscribeAsync(topicType).ConfigureAwait(true);
         var subscriptions = await agent.GetSubscriptionsAsync().ConfigureAwait(true);
         var found = false;
         foreach (var subscription in subscriptions)
         {
-            if (subscription.TypeSubscription.TopicType == "TestEvent")
+            if (subscription.TypeSubscription.TopicType == topicType)
             {
                 found = true;
             }
@@ -134,12 +134,12 @@ public async Task PublishMessageAsync_and_ReceiveMessageTest()
         Assert.True(found);
         await agent.PublishMessageAsync(new TextMessage()
         {
-            Source = "TestEvent",
+            Source = topicType,
             TextMessage_ = "buffer"
-        }).ConfigureAwait(true);
+        }, topicType).ConfigureAwait(true);
         await Task.Delay(100);
-        Assert.True(TestAgent.ReceivedMessages.ContainsKey("TestEvent"));
-        _fixture.Stop();
+        Assert.True(TestAgent.ReceivedMessages.ContainsKey(topicType));
+        runtime.Stop();
     }
 
     [Fact]
@@ -158,7 +158,8 @@ public async Task InvokeCorrectHandler()
     [Fact]
     public async Task DelegateMessageToTestAgentAsync()
     {
-        var client = _fixture.AppHost.Services.GetRequiredService<Client>();
+        var runtime = new InMemoryAgentRuntimeFixture();
+        var client = runtime.AppHost.Services.GetRequiredService<Client>();
         await client.PublishMessageAsync(new TextMessage()
         {
             Source = nameof(DelegateMessageToTestAgentAsync),
@@ -214,7 +215,7 @@ public Task Handle(int item)
 /// This fixture is used to provide a runtime for the agent tests.
 /// However, it is shared between tests. So operations from one test can affect another.
 /// </remarks>
-public sealed class InMemoryAgentRuntimeFixture
+public sealed class InMemoryAgentRuntimeFixture : IDisposable
 {
     public InMemoryAgentRuntimeFixture()
     {
@@ -239,13 +240,19 @@ public InMemoryAgentRuntimeFixture()
         return (worker, agent);
     }
     /// <summary>
-    /// Stop - stops the agent
+    /// Stop - stops the agent and ensures cleanup
     /// </summary>
-    /// <returns>void</returns>
     public void Stop()
     {
-        IHostApplicationLifetime hostApplicationLifetime = AppHost.Services.GetRequiredService<IHostApplicationLifetime>();
-        hostApplicationLifetime.StopApplication();
+        AppHost?.StopAsync().GetAwaiter().GetResult();
+    }
+
+    /// <summary>
+    /// Dispose - Ensures cleanup after each test
+    /// </summary>
+    public void Dispose()
+    {
+        Stop();
     }
 }
 
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index ce9f80e53a87..71a0863b27ab 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -42,11 +42,9 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         var client = new TestGrpcClient();
-        var assembly = typeof(PBAgent).Assembly;
-        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
         var task = OpenChannel(service: service, client);
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
+        await service.RegisterAgent(await CreateRegistrationRequest(service,typeof(PBAgent), client.CallContext.Peer), client.CallContext);
+        await service.RegisterAgent(await CreateRegistrationRequest(service, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
 
         var inputEvent = new NewMessageReceived { Message = $"Start-{client.CallContext.Peer}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
 
@@ -54,6 +52,8 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var newMessageReceived = await client.ReadNext();
         newMessageReceived!.CloudEvent.Type.Should().Be(GetFullName(typeof(NewMessageReceived)));
         newMessageReceived.CloudEvent.Source.Should().Be("gh-gh-gh");
+        var secondMessage = await client.ReadNext();
+        secondMessage!.CloudEvent.Type.Should().Be(GetFullName(typeof(NewMessageReceived)));
 
         // Simulate an agent, by publishing a new message in the request stream
         var helloEvent = new Hello { Message = $"Hello test-{client.CallContext.Peer}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");
@@ -65,22 +65,6 @@ public async Task Test_Message_Exchange_Through_Gateway()
         await task;
     }
 
-    [Fact]
-    public async Task Test_Message_Goes_To_Right_Worker()
-    {
-        var logger = Mock.Of<ILogger<GrpcGateway>>();
-        var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
-        var service = new GrpcGatewayService(gateway);
-        var client = new TestGrpcClient();
-        var assembly = typeof(PBAgent).Assembly;
-        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-        var task = OpenChannel(service: service, client);
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
-        await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
-        client.Dispose();
-        await task;
-    }
-
     [Fact]
     public async Task Test_RegisterAgent_Should_Succeed()
     {
@@ -88,10 +72,8 @@ public async Task Test_RegisterAgent_Should_Succeed()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         var client = new TestGrpcClient();
-        var assembly = typeof(PBAgent).Assembly;
-        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
         var task = OpenChannel(service: service, client);
-        var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
+        var response = await service.RegisterAgent(await CreateRegistrationRequest(service, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         response.Success.Should().BeTrue();
         client.Dispose();
         await task;
@@ -104,9 +86,7 @@ public async Task Test_RegisterAgent_Should_Fail_For_Wrong_ConnectionId()
         var gateway = new GrpcGateway(_fixture.Cluster.Client, logger);
         var service = new GrpcGatewayService(gateway);
         var client = new TestGrpcClient();
-        var assembly = typeof(PBAgent).Assembly;
-        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
-        var response = await service.RegisterAgent(CreateRegistrationRequest(eventTypes, typeof(PBAgent), "faulty_connection_id"), client.CallContext);
+        var response = await service.RegisterAgent(await CreateRegistrationRequest(service, typeof(PBAgent), "faulty_connection_id"), client.CallContext);
         response.Success.Should().BeFalse();
         client.Dispose();
     }
@@ -133,15 +113,65 @@ public async Task Test_GetState()
         response.Should().NotBeNull();
     }
 
-    private RegisterAgentTypeRequest CreateRegistrationRequest(AgentsMetadata eventTypes, Type type, string requestId)
+    private async Task<RegisterAgentTypeRequest> CreateRegistrationRequest(GrpcGatewayService service, Type type, string requestId)
     {
         var registration = new RegisterAgentTypeRequest
         {
             Type = type.Name,
             RequestId = requestId
         };
-        registration.Events.AddRange(eventTypes.GetEventsForAgent(type)?.ToList());
-        registration.Topics.AddRange(eventTypes.GetTopicsForAgent(type)?.ToList());
+        var assembly = type.Assembly;
+        var eventTypes = ReflectionHelper.GetAgentsMetadata(assembly);
+        var events = eventTypes.GetEventsForAgent(type)?.ToList();
+        var topics = eventTypes.GetTopicsForAgent(type)?.ToList();
+        if (events is not null && topics is not null) { events.AddRange(topics); }
+        var client = new TestGrpcClient();
+
+        if (events != null)
+        {
+            foreach (var e in events)
+            {
+                var subscriptionRequest = new Message
+                {
+                    AddSubscriptionRequest = new AddSubscriptionRequest
+                    {
+                        RequestId = Guid.NewGuid().ToString(),
+                        Subscription = new Subscription
+                        {
+                            TypeSubscription = new TypeSubscription
+                            {
+                                AgentType = type.Name,
+                                TopicType = type.Name + "." + e
+                            }
+                        }
+                    }
+                };
+                await service.AddSubscription(subscriptionRequest.AddSubscriptionRequest, client.CallContext);
+            }
+        }
+        var topicTypes = type.GetCustomAttributes(typeof(TopicSubscriptionAttribute), true).Cast<TopicSubscriptionAttribute>().Select(t => t.Topic).ToList();
+        if (topicTypes != null)
+        {
+            foreach (var topicType in topicTypes)
+            {
+                var subscriptionRequest = new Message
+                {
+                    AddSubscriptionRequest = new AddSubscriptionRequest
+                    {
+                        RequestId = Guid.NewGuid().ToString(),
+                        Subscription = new Subscription
+                        {
+                            TypeSubscription = new TypeSubscription
+                            {
+                                AgentType = type.Name,
+                                TopicType = topicType
+                            }
+                        }
+                    }
+                };
+                await service.AddSubscription(subscriptionRequest.AddSubscriptionRequest, client.CallContext);
+            }
+        }
         return registration;
     }
 

From 0ffba79f5b80ab448f355648152228418d964b48 Mon Sep 17 00:00:00 2001
From: Ryan Sweet <rysweet@microsoft.com>
Date: Fri, 24 Jan 2025 17:35:10 -0800
Subject: [PATCH 109/110] format

---
 .../Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs | 2 +-
 .../GrpcGatewayServiceTests.cs                                  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
index 913b7b5bbeb4..0f730df718f2 100644
--- a/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
+++ b/dotnet/src/Microsoft.AutoGen/Runtime.Grpc/Services/Grpc/GrpcGateway.cs
@@ -380,7 +380,7 @@ public async ValueTask<RemoveSubscriptionResponse> UnsubscribeAsync(RemoveSubscr
                 Error = ex.Message
             };
         }
-    } 
+    }
     public ValueTask<List<Subscription>> GetSubscriptionsAsync(GetSubscriptionsRequest request, CancellationToken cancellationToken = default)
     {
         return _gatewayRegistry.GetSubscriptions(request);
diff --git a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
index 71a0863b27ab..89f17f2fe755 100644
--- a/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
+++ b/dotnet/test/Microsoft.AutoGen.Runtime.Grpc.Tests/GrpcGatewayServiceTests.cs
@@ -43,7 +43,7 @@ public async Task Test_Message_Exchange_Through_Gateway()
         var service = new GrpcGatewayService(gateway);
         var client = new TestGrpcClient();
         var task = OpenChannel(service: service, client);
-        await service.RegisterAgent(await CreateRegistrationRequest(service,typeof(PBAgent), client.CallContext.Peer), client.CallContext);
+        await service.RegisterAgent(await CreateRegistrationRequest(service, typeof(PBAgent), client.CallContext.Peer), client.CallContext);
         await service.RegisterAgent(await CreateRegistrationRequest(service, typeof(GMAgent), client.CallContext.Peer), client.CallContext);
 
         var inputEvent = new NewMessageReceived { Message = $"Start-{client.CallContext.Peer}" }.ToCloudEvent("gh-gh-gh", "gh-gh-gh");

From da4923a4e37c8e082052c5f211aa2247d644e7a8 Mon Sep 17 00:00:00 2001
From: Jack Gerrits <jack@jackgerrits.com>
Date: Fri, 24 Jan 2025 20:58:21 -0500
Subject: [PATCH 110/110] undo changes

---
 protos/agent_worker.proto                                   | 1 +
 .../src/autogen_ext/runtimes/grpc/_worker_runtime.py        | 6 +++---
 .../runtimes/grpc/_worker_runtime_host_servicer.py          | 6 +++---
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/protos/agent_worker.proto b/protos/agent_worker.proto
index f12943da2bc8..0cf1581aff39 100644
--- a/protos/agent_worker.proto
+++ b/protos/agent_worker.proto
@@ -143,3 +143,4 @@ message Message {
         AddSubscriptionResponse addSubscriptionResponse = 7;
     }
 }
+
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py
index 5235efc68eba..ee41a1f58628 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py
@@ -275,7 +275,7 @@ async def _run_read_loop(self) -> None:
                 message = await self._host_connection.recv()
                 oneofcase = agent_worker_pb2.Message.WhichOneof(message, "message")
                 match oneofcase:
-                    case "registerAgentTypeRequest" | "SubscriptionRequest":
+                    case "registerAgentTypeRequest" | "addSubscriptionRequest":
                         logger.warning(f"Cant handle {oneofcase}, skipping.")
                     case "request":
                         task = asyncio.create_task(self._process_request(message.request))
@@ -299,9 +299,9 @@ async def _run_read_loop(self) -> None:
                         self._background_tasks.add(task)
                         task.add_done_callback(self._raise_on_exception)
                         task.add_done_callback(self._background_tasks.discard)
-                    case "SubscriptionResponse":
+                    case "addSubscriptionResponse":
                         task = asyncio.create_task(
-                            self._process_add_subscription_response(message.SubscriptionResponse)
+                            self._process_add_subscription_response(message.addSubscriptionResponse)
                         )
                         self._background_tasks.add(task)
                         task.add_done_callback(self._raise_on_exception)
diff --git a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py
index a401a8a6033c..e5c7d53df3ad 100644
--- a/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py
+++ b/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime_host_servicer.py
@@ -138,13 +138,13 @@ async def _receive_messages(
                     self._background_tasks.add(task)
                     task.add_done_callback(self._raise_on_exception)
                     task.add_done_callback(self._background_tasks.discard)
-                case "SubscriptionRequest":
-                    add_subscription: agent_worker_pb2.SubscriptionRequest = message.SubscriptionRequest
+                case "addSubscriptionRequest":
+                    add_subscription: agent_worker_pb2.AddSubscriptionRequest = message.addSubscriptionRequest
                     task = asyncio.create_task(self._process_add_subscription_request(add_subscription, client_id))
                     self._background_tasks.add(task)
                     task.add_done_callback(self._raise_on_exception)
                     task.add_done_callback(self._background_tasks.discard)
-                case "registerAgentTypeResponse" | "SubscriptionResponse":
+                case "registerAgentTypeResponse" | "addSubscriptionResponse":
                     logger.warning(f"Received unexpected message type: {oneofcase}")
                 case None:
                     logger.warning("Received empty message")