diff --git a/dotnet/.tools/test-aot-compatibility.ps1 b/dotnet/.tools/test-aot-compatibility.ps1 index 071edcd956d..d70139fd1fd 100644 --- a/dotnet/.tools/test-aot-compatibility.ps1 +++ b/dotnet/.tools/test-aot-compatibility.ps1 @@ -15,7 +15,7 @@ foreach ($line in $($publishOutput -split "`r`n")) } } -pushd $rootDirectory/test/AutoGen.AotCompatibility.Tests/bin/Release/$targetNetFramework/linux-x64 +pushd $rootDirectory/artifacts/bin/AutoGen.AotCompatibility.Tests/release Write-Host "Executing test App..." ./AutoGen.AotCompatibility.Tests diff --git a/dotnet/AutoGen.sln b/dotnet/AutoGen.sln index accf92218ab..5b26e27165b 100644 --- a/dotnet/AutoGen.sln +++ b/dotnet/AutoGen.sln @@ -122,15 +122,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAIAgents", "samples\He EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAgent", "samples\Hello\HelloAgent\HelloAgent.csproj", "{8F7560CF-EEBB-4333-A69F-838CA40FD85D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AIModelClientHostingExtensions", "src\Microsoft.AutoGen\Extensions\AIModelClientHostingExtensions\AIModelClientHostingExtensions.csproj", "{97550E87-48C6-4EBF-85E1-413ABAE9DBFD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AutoGen.Extensions.MEAI", "src\Microsoft.AutoGen\Extensions\MEAI\Microsoft.AutoGen.Extensions.MEAI.csproj", "{97550E87-48C6-4EBF-85E1-413ABAE9DBFD}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{686480D7-8FEC-4ED3-9C5D-CEBE1057A7ED}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloAgentState", "samples\Hello\HelloAgentState\HelloAgentState.csproj", "{64EF61E7-00A6-4E5E-9808-62E10993A0E5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.ServiceDefaults", "src\Microsoft.AutoGen\Extensions\ServiceDefaults\Microsoft.AutoGen.ServiceDefaults.csproj", "{65059914-5527-4A00-9308-9FAF23D5E85A}" +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("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AutoGen.Agents.Tests", "test\Microsoft.AutoGen.Agents.Tests\Microsoft.AutoGen.Agents.Tests.csproj", "{394FDAF8-74F9-4977-94A5-3371737EB774}" +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 Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/dotnet/Directory.Build.props b/dotnet/Directory.Build.props index 1e84f78232a..e548a4b7ea8 100644 --- a/dotnet/Directory.Build.props +++ b/dotnet/Directory.Build.props @@ -3,6 +3,7 @@ + true netstandard2.0;net8.0 net8.0 preview @@ -20,7 +21,6 @@ true true false - embedded true @@ -29,6 +29,11 @@ $(MSBuildThisFileDirectory) + + $(VersionPrefixForAutoGen0_2) + true + + $(NoWarn);CA1829 diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index 5321860e427..0f6ecd10b1d 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -106,8 +106,8 @@ + - diff --git a/dotnet/README.md b/dotnet/README.md index a5705114d72..c34679389fc 100644 --- a/dotnet/README.md +++ b/dotnet/README.md @@ -1,12 +1,12 @@ # AutoGen for .NET Thre are two sets of packages here: -Autogen.\* the older packages derived from Autogen 0.2 for .NET - these will gradually be deprecated and ported into the new packages +AutoGen.\* the older packages derived from AutoGen 0.2 for .NET - these will gradually be deprecated and ported into the new packages Microsoft.AutoGen.* the new packages for .NET that use the event-driven model - These APIs are not yet stable and are subject to change. To get started with the new packages, please see the [samples](./samples/) and in particular the [Hello](./samples/Hello) sample. -The remaining content is for the older Autogen.* packages. +You can install both new and old packages from the following feeds: [![dotnet-ci](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml/badge.svg)](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml) [![NuGet version](https://badge.fury.io/nu/AutoGen.Core.svg)](https://badge.fury.io/nu/AutoGen.Core) @@ -14,9 +14,7 @@ The remaining content is for the older Autogen.* packages. > [!NOTE] > Nightly build is available at: > -> - ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/nightly-yellow?style=flat) ![Static Badge](https://img.shields.io/badge/github-grey?style=flat): -> - ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/nightly-yellow?style=flat) ![Static Badge](https://img.shields.io/badge/myget-grey?style=flat): -> - ![Static Badge](https://img.shields.io/badge/internal-blue?style=flat) ![Static Badge](https://img.shields.io/badge/nightly-yellow?style=flat) ![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat) : +> - [![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat)](https://dev.azure.com/AGPublish/AGPublic/_artifacts/feed/AutoGen-Nightly) : Firstly, following the [installation guide](./website/articles/Installation.md) to install AutoGen packages. diff --git a/dotnet/eng/MetaInfo.props b/dotnet/eng/MetaInfo.props index 4f3d216aa08..db46778a06c 100644 --- a/dotnet/eng/MetaInfo.props +++ b/dotnet/eng/MetaInfo.props @@ -1,7 +1,8 @@ - 0.2.2 + 0.4.0 + 0.2.2 AutoGen https://microsoft.github.io/autogen-for-net/ https://github.com/microsoft/autogen diff --git a/dotnet/nuget/nuget-package.props b/dotnet/nuget/nuget-package.props index 50cbafc73b6..380380794dc 100644 --- a/dotnet/nuget/nuget-package.props +++ b/dotnet/nuget/nuget-package.props @@ -7,7 +7,7 @@ Microsoft AutoGen A programming framework for agentic AI - AI, Artificial Intelligence, SDK + AI, Artificial Intelligence, Agents, Multiagent, SDK $(AssemblyName) diff --git a/dotnet/samples/Hello/Backend/Backend.csproj b/dotnet/samples/Hello/Backend/Backend.csproj index c138379cb0e..36045933480 100644 --- a/dotnet/samples/Hello/Backend/Backend.csproj +++ b/dotnet/samples/Hello/Backend/Backend.csproj @@ -4,7 +4,7 @@ Exe - net8.0 + net8.0 enable enable diff --git a/dotnet/samples/Hello/Backend/appsettings.Development.json b/dotnet/samples/Hello/Backend/appsettings.Development.json deleted file mode 100644 index ae32fe371a7..00000000000 --- a/dotnet/samples/Hello/Backend/appsettings.Development.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "Logging": { - "LogLevel": { - "Default": "Warning", - "Microsoft": "Warning", - "Microsoft.Orleans": "Warning" - } - }, - "AllowedHosts": "*", - "Kestrel": { - "EndpointDefaults": { - "Protocols": "Http2" - } - } -} diff --git a/dotnet/samples/Hello/Backend/appsettings.json b/dotnet/samples/Hello/Backend/appsettings.json index 585fa1ae03d..ae32fe371a7 100644 --- a/dotnet/samples/Hello/Backend/appsettings.json +++ b/dotnet/samples/Hello/Backend/appsettings.json @@ -1,4 +1,11 @@ { + "Logging": { + "LogLevel": { + "Default": "Warning", + "Microsoft": "Warning", + "Microsoft.Orleans": "Warning" + } + }, "AllowedHosts": "*", "Kestrel": { "EndpointDefaults": { diff --git a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj index e49cfd456ab..c33bfeed5a8 100644 --- a/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj +++ b/dotnet/samples/Hello/HelloAIAgents/HelloAIAgents.csproj @@ -13,6 +13,6 @@ - + diff --git a/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj b/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj index 3baf0522c98..dcb693a5222 100644 --- a/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj +++ b/dotnet/samples/Hello/HelloAgent/HelloAgent.csproj @@ -1,4 +1,4 @@ - + Exe net8.0 diff --git a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj index bf1bed17824..7508ae5af56 100644 --- a/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj +++ b/dotnet/samples/dev-team/DevTeam.AgentHost/DevTeam.AgentHost.csproj @@ -10,7 +10,7 @@ - + diff --git a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj index d8034a01b99..46a20c650fb 100644 --- a/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj +++ b/dotnet/samples/dev-team/DevTeam.Agents/DevTeam.Agents.csproj @@ -10,7 +10,7 @@ - + diff --git a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj index c486471984f..10e05cfb210 100644 --- a/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj +++ b/dotnet/samples/dev-team/DevTeam.Backend/DevTeam.Backend.csproj @@ -29,7 +29,7 @@ - + diff --git a/dotnet/samples/dev-team/DevTeam.Backend/Program.cs b/dotnet/samples/dev-team/DevTeam.Backend/Program.cs index b24476692d0..7f4404f8e47 100644 --- a/dotnet/samples/dev-team/DevTeam.Backend/Program.cs +++ b/dotnet/samples/dev-team/DevTeam.Backend/Program.cs @@ -67,9 +67,9 @@ }); ; app.UseSwagger(); -app.UseSwaggerUI(c => +/* app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1"); -}); +}); */ app.Run(); diff --git a/dotnet/src/AutoGen.Core/Message/ImageMessage.cs b/dotnet/src/AutoGen.Core/Message/ImageMessage.cs index 369a3782d50..37be3a7c7ed 100644 --- a/dotnet/src/AutoGen.Core/Message/ImageMessage.cs +++ b/dotnet/src/AutoGen.Core/Message/ImageMessage.cs @@ -2,39 +2,65 @@ // ImageMessage.cs using System; +using System.Text.RegularExpressions; namespace AutoGen.Core; public class ImageMessage : IMessage { - public ImageMessage(Role role, string url, string? from = null, string? mimeType = null) - : this(role, new Uri(url), from, mimeType) - { - } + private static readonly Regex s_DataUriRegex = new Regex(@"^data:(?[^;]+);base64,(?.*)$", RegexOptions.Compiled); - public ImageMessage(Role role, Uri uri, string? from = null, string? mimeType = null) + /// + /// Create an ImageMessage from a url. + /// The url can be a regular url or a data uri. + /// If the url is a data uri, the scheme must be "data" and the format must be data:[][;base64], + /// + public ImageMessage(Role role, string url, string? from = null, string? mimeType = null) { this.Role = role; this.From = from; - this.Url = uri.ToString(); - // try infer mimeType from uri extension if not provided - if (mimeType is null) + // url might be a data uri or a regular url + if (url.StartsWith("data:", StringComparison.OrdinalIgnoreCase)) + { + // the url must be in the format of data:[][;base64], + var match = s_DataUriRegex.Match(url); + + if (!match.Success) + { + throw new ArgumentException("Invalid DataUri format, expected data:[][;base64],", nameof(url)); + } + + this.Data = new BinaryData(Convert.FromBase64String(match.Groups["data"].Value), match.Groups["mediatype"].Value); + + this.MimeType = match.Groups["mediatype"].Value; + } + else { - mimeType = uri switch + this.Url = url; + // try infer mimeType from uri extension if not provided + if (mimeType is null) { - _ when uri.AbsoluteUri.EndsWith(".png", StringComparison.OrdinalIgnoreCase) => "image/png", - _ when uri.AbsoluteUri.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) => "image/jpeg", - _ when uri.AbsoluteUri.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) => "image/jpeg", - _ when uri.AbsoluteUri.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) => "image/gif", - _ when uri.AbsoluteUri.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) => "image/bmp", - _ when uri.AbsoluteUri.EndsWith(".webp", StringComparison.OrdinalIgnoreCase) => "image/webp", - _ when uri.AbsoluteUri.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) => "image/svg+xml", - _ => throw new ArgumentException("MimeType is required for ImageMessage", nameof(mimeType)) - }; + mimeType = url switch + { + _ when url.EndsWith(".png", StringComparison.OrdinalIgnoreCase) => "image/png", + _ when url.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) => "image/jpeg", + _ when url.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) => "image/jpeg", + _ when url.EndsWith(".gif", StringComparison.OrdinalIgnoreCase) => "image/gif", + _ when url.EndsWith(".bmp", StringComparison.OrdinalIgnoreCase) => "image/bmp", + _ when url.EndsWith(".webp", StringComparison.OrdinalIgnoreCase) => "image/webp", + _ when url.EndsWith(".svg", StringComparison.OrdinalIgnoreCase) => "image/svg+xml", + _ => throw new ArgumentException("MimeType is required for ImageMessage", nameof(mimeType)) + }; + } + + this.MimeType = mimeType; } + } - this.MimeType = mimeType; + public ImageMessage(Role role, Uri uri, string? from = null, string? mimeType = null) + : this(role, uri.ToString(), from, mimeType) + { } public ImageMessage(Role role, BinaryData data, string? from = null) diff --git a/dotnet/src/AutoGen.SemanticKernel/Middleware/SemanticKernelChatMessageContentConnector.cs b/dotnet/src/AutoGen.SemanticKernel/Middleware/SemanticKernelChatMessageContentConnector.cs index 073709ebad0..92947092ba2 100644 --- a/dotnet/src/AutoGen.SemanticKernel/Middleware/SemanticKernelChatMessageContentConnector.cs +++ b/dotnet/src/AutoGen.SemanticKernel/Middleware/SemanticKernelChatMessageContentConnector.cs @@ -181,7 +181,19 @@ private IEnumerable ProcessMessageForOthers(TextMessage mess private IEnumerable ProcessMessageForOthers(ImageMessage message) { var collectionItems = new ChatMessageContentItemCollection(); - collectionItems.Add(new ImageContent(new Uri(message.Url ?? message.BuildDataUri()))); + if (message.Url is not null) + { + collectionItems.Add(new ImageContent(new Uri(message.Url))); + } + else if (message.BuildDataUri() is string dataUri) + { + collectionItems.Add(new ImageContent(dataUri)); + } + else + { + throw new InvalidOperationException("ImageMessage must have Url or DataUri"); + } + return [new ChatMessageContent(AuthorRole.User, collectionItems)]; } diff --git a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj index c680e201301..d9596f607cc 100644 --- a/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj +++ b/dotnet/src/Microsoft.AutoGen/Abstractions/Microsoft.AutoGen.Abstractions.csproj @@ -1,15 +1,13 @@ - net8.0 + net8.0 enable enable - AutoGen.Core - https://github.com/microsoft/agnext - Microsoft - AutoGenn Core Library + + diff --git a/dotnet/src/Microsoft.AutoGen/Agents/App.cs b/dotnet/src/Microsoft.AutoGen/Agents/App.cs index fc36d336779..8a233bcd489 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/App.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/App.cs @@ -12,6 +12,7 @@ public static class AgentsApp { // need a variable to store the runtime instance public static WebApplication? Host { get; private set; } + [MemberNotNull(nameof(Host))] public static async ValueTask StartAsync(WebApplicationBuilder? builder = null, AgentTypes? agentTypes = null, bool local = false) { @@ -58,7 +59,7 @@ public static async ValueTask ShutdownAsync() await Host.StopAsync(); } - private static AgentApplicationBuilder AddAgents(this AgentApplicationBuilder builder, AgentTypes? agentTypes) + private static IHostApplicationBuilder AddAgents(this IHostApplicationBuilder builder, AgentTypes? agentTypes) { agentTypes ??= AgentTypes.GetAgentTypesFromAssembly() ?? throw new InvalidOperationException("No agent types found in the assembly"); diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj index 68b26f88b9c..aa79cf9665a 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj +++ b/dotnet/src/Microsoft.AutoGen/Agents/Microsoft.AutoGen.Agents.csproj @@ -1,19 +1,17 @@ - net8.0 + net8.0 enable enable - Microsoft.AutoGen.Agents - https://github.com/microsoft/autogen - Microsoft - Micrososft AutoGen Agents SDK - ai-agents;event-driven-agents + + + - + diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs index fab74a3a34a..fab29e86ce7 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/AgentWorkerHostingExtensions.cs @@ -3,8 +3,6 @@ using System.Diagnostics; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Hosting; @@ -13,25 +11,9 @@ namespace Microsoft.AutoGen.Agents; public static class AgentWorkerHostingExtensions { - public static WebApplicationBuilder AddAgentService(this WebApplicationBuilder builder, bool local = false, bool useGrpc = true) + public static IHostApplicationBuilder AddAgentService(this IHostApplicationBuilder builder, bool local = false, bool useGrpc = true) { - if (local) - { - //TODO: make configuration more flexible - builder.WebHost.ConfigureKestrel(serverOptions => - { - serverOptions.ListenLocalhost(5001, listenOptions => - { - listenOptions.Protocols = HttpProtocols.Http2; - listenOptions.UseHttps(); - }); - }); - builder.AddOrleans(local); - } - else - { - builder.AddOrleans(); - } + builder.AddOrleans(local); builder.Services.TryAddSingleton(DistributedContextPropagator.Current); @@ -45,10 +27,11 @@ public static WebApplicationBuilder AddAgentService(this WebApplicationBuilder b return builder; } - public static WebApplicationBuilder AddLocalAgentService(this WebApplicationBuilder builder, bool useGrpc = true) + public static IHostApplicationBuilder AddLocalAgentService(this IHostApplicationBuilder builder, bool useGrpc = true) { return builder.AddAgentService(local: false, useGrpc); } + public static WebApplication MapAgentService(this WebApplication app, bool local = false, bool useGrpc = true) { if (useGrpc) { app.MapGrpcService(); } diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs index f441ad106e9..f21096ccfbd 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/HostBuilderExtensions.cs @@ -16,7 +16,22 @@ namespace Microsoft.AutoGen.Agents; public static class HostBuilderExtensions { private const string _defaultAgentServiceAddress = "https://localhost:53071"; - public static AgentApplicationBuilder AddAgentWorker(this IHostApplicationBuilder builder, string? agentServiceAddress = null, bool local = false) + + public static IHostApplicationBuilder AddAgent< + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TAgent>(this IHostApplicationBuilder builder, string typeName) where TAgent : AgentBase + { + builder.Services.AddKeyedSingleton("AgentTypes", (sp, key) => Tuple.Create(typeName, typeof(TAgent))); + + return builder; + } + + public static IHostApplicationBuilder AddAgent(this IHostApplicationBuilder builder, string typeName, Type agentType) + { + builder.Services.AddKeyedSingleton("AgentTypes", (sp, key) => Tuple.Create(typeName, agentType)); + return builder; + } + + public static IHostApplicationBuilder AddAgentWorker(this IHostApplicationBuilder builder, string? agentServiceAddress = null, bool local = false) { agentServiceAddress ??= builder.Configuration["AGENT_HOST"] ?? _defaultAgentServiceAddress; builder.Services.TryAddSingleton(DistributedContextPropagator.Current); @@ -99,7 +114,9 @@ public static AgentApplicationBuilder AddAgentWorker(this IHostApplicationBuilde return new EventTypes(typeRegistry, types, eventsMap); }); builder.Services.AddSingleton(); - return new AgentApplicationBuilder(builder); + builder.Services.AddSingleton(new AgentApplicationBuilder(builder)); + + return builder; } private static MessageDescriptor? GetMessageDescriptor(Type type) diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/OrleansRuntimeHostingExtenions.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/OrleansRuntimeHostingExtenions.cs index 7a658596db5..374e49f7a50 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/OrleansRuntimeHostingExtenions.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/OrleansRuntimeHostingExtenions.cs @@ -15,11 +15,17 @@ public static class OrleansRuntimeHostingExtenions { public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builder, bool local = false) { + return builder.AddOrleans(local); + } + public static IHostApplicationBuilder AddOrleans(this IHostApplicationBuilder builder, bool local = false) + { builder.Services.AddSerializer(serializer => serializer.AddProtobufSerializer()); + builder.Services.AddSingleton(); + // Ensure Orleans is added before the hosted service to guarantee that it starts first. //TODO: make all of this configurable - builder.Host.UseOrleans(siloBuilder => + builder.UseOrleans((siloBuilder) => { // Development mode or local mode uses in-memory storage and streams if (builder.Environment.IsDevelopment() || local) @@ -51,16 +57,16 @@ public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builde options.SystemResponseTimeout = TimeSpan.FromMinutes(3); }); siloBuilder.Configure(options => - { - options.ResponseTimeout = TimeSpan.FromMinutes(3); - }); + { + options.ResponseTimeout = TimeSpan.FromMinutes(3); + }); siloBuilder.UseCosmosClustering(o => - { - o.ConfigureCosmosClient(cosmosDbconnectionString); - o.ContainerName = "AutoGen"; - o.DatabaseName = "clustering"; - o.IsResourceCreationEnabled = true; - }); + { + o.ConfigureCosmosClient(cosmosDbconnectionString); + o.ContainerName = "AutoGen"; + o.DatabaseName = "clustering"; + o.IsResourceCreationEnabled = true; + }); siloBuilder.UseCosmosReminderService(o => { @@ -84,8 +90,7 @@ public static WebApplicationBuilder AddOrleans(this WebApplicationBuilder builde .AddMemoryGrainStorage("PubSubStore"); } }); - builder.Services.AddSingleton(); - //builder.Services.AddSingleton(); + return builder; } } diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs index c5114e3e742..cb752312643 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/RegistryGrain.cs @@ -5,7 +5,7 @@ namespace Microsoft.AutoGen.Agents; -public sealed class RegistryGrain : Grain, IRegistryGrain +internal sealed class RegistryGrain : Grain, IRegistryGrain { // TODO: use persistent state for some of these or (better) extend Orleans to implement some of this natively. private readonly Dictionary _workerStates = new(); diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs index 25531bd6c49..905dc8e914a 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/SubscriptionsGrain.cs @@ -3,7 +3,7 @@ namespace Microsoft.AutoGen.Agents; -public sealed class SubscriptionsGrain([PersistentState("state", "PubSubStore")] IPersistentState state) : Grain, ISubscriptionsGrain +internal sealed class SubscriptionsGrain([PersistentState("state", "PubSubStore")] IPersistentState state) : Grain, ISubscriptionsGrain { private readonly Dictionary> _subscriptions = new(); public ValueTask>> GetSubscriptions(string agentType) diff --git a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/iSubscriptionsGrain.cs b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/iSubscriptionsGrain.cs index 9b3157931ae..302df9ebff9 100644 --- a/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/iSubscriptionsGrain.cs +++ b/dotnet/src/Microsoft.AutoGen/Agents/Services/Orleans/iSubscriptionsGrain.cs @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// iSubscriptionsGrain.cs +// ISubscriptionsGrain.cs namespace Microsoft.AutoGen.Agents; public interface ISubscriptionsGrain : IGrainWithIntegerKey diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Extensions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/AspireHostingExtensions.cs similarity index 98% rename from dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Extensions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/Aspire/AspireHostingExtensions.cs index a4eccacb7fd..0e6781d740e 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Extensions.cs +++ b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/AspireHostingExtensions.cs @@ -1,5 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// Extensions.cs +// AspireHostingExtensions.cs using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Diagnostics.HealthChecks; @@ -15,7 +15,7 @@ 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 class AspireHostingExtensions { public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder) { diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj similarity index 88% rename from dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj rename to dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj index b70161c7e77..0cab61bc27b 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/ServiceDefaults/Microsoft.AutoGen.ServiceDefaults.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/Aspire/Microsoft.AutoGen.Extensions.Aspire.csproj @@ -1,10 +1,13 @@ - net8.0 + net8.0 enable enable true + + + diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/MEAIHostingExtensions.cs similarity index 94% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/MEAIHostingExtensions.cs index c3c9c197392..d39f358f8cb 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.cs +++ b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/MEAIHostingExtensions.cs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. -// AIModelClientHostingExtensions.cs +// MEAIHostingExtensions.cs using Microsoft.Extensions.AI; namespace Microsoft.Extensions.Hosting; -public static class AIModelClient +public static class MEAIHostingExtensions { public static IHostApplicationBuilder AddChatCompletionService(this IHostApplicationBuilder builder, string serviceName) { diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj similarity index 88% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj index 970ae5db4b7..b8233a8e6c5 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/AIModelClientHostingExtensions.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Microsoft.AutoGen.Extensions.MEAI.csproj @@ -1,9 +1,12 @@ - net8.0 + net8.0 enable enable + + + diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/Options/AIClientOptions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Options/AIClientOptions.cs similarity index 100% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/Options/AIClientOptions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/Options/AIClientOptions.cs diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/ServiceCollectionChatCompletionExtensions.cs b/dotnet/src/Microsoft.AutoGen/Extensions/MEAI/ServiceCollectionChatCompletionExtensions.cs similarity index 100% rename from dotnet/src/Microsoft.AutoGen/Extensions/AIModelClientHostingExtensions/ServiceCollectionChatCompletionExtensions.cs rename to dotnet/src/Microsoft.AutoGen/Extensions/MEAI/ServiceCollectionChatCompletionExtensions.cs diff --git a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj index 3c7fe517799..c4ac5536e70 100644 --- a/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj +++ b/dotnet/src/Microsoft.AutoGen/Extensions/SemanticKernel/Microsoft.AutoGen.Extensions.SemanticKernel.csproj @@ -1,22 +1,23 @@ - - - - - - - net8.0 + net8.0 enable enable - - - + + + + + + + + + + diff --git a/dotnet/test/AutoGen.Tests/ImageMessageTests.cs b/dotnet/test/AutoGen.Tests/ImageMessageTests.cs index e8a30c87012..bb256a170f2 100644 --- a/dotnet/test/AutoGen.Tests/ImageMessageTests.cs +++ b/dotnet/test/AutoGen.Tests/ImageMessageTests.cs @@ -35,4 +35,18 @@ public async Task ItCreateFromUrl() imageMessage.MimeType.Should().Be("image/png"); imageMessage.Data.Should().BeNull(); } + + [Fact] + public async Task ItCreateFromBase64Url() + { + var image = Path.Combine("testData", "images", "background.png"); + var binary = File.ReadAllBytes(image); + var base64 = Convert.ToBase64String(binary); + + var base64Url = $"data:image/png;base64,{base64}"; + var imageMessage = new ImageMessage(Role.User, base64Url); + + imageMessage.BuildDataUri().Should().Be(base64Url); + imageMessage.MimeType.Should().Be("image/png"); + } } diff --git a/dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentBaseTests.cs b/dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentBaseTests.cs index b10f82e7d43..e58fdb00f0a 100644 --- a/dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentBaseTests.cs +++ b/dotnet/test/Microsoft.AutoGen.Agents.Tests/AgentBaseTests.cs @@ -1,17 +1,24 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // AgentBaseTests.cs +using System.Collections.Concurrent; using FluentAssertions; using Google.Protobuf.Reflection; using Microsoft.AutoGen.Abstractions; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Moq; using Xunit; +using static Microsoft.AutoGen.Agents.Tests.AgentBaseTests; namespace Microsoft.AutoGen.Agents.Tests; -public class AgentBaseTests +[Collection(ClusterFixtureCollection.Name)] +public class AgentBaseTests(InMemoryAgentRuntimeFixture fixture) { + private readonly InMemoryAgentRuntimeFixture _fixture = fixture; + [Fact] public async Task ItInvokeRightHandlerTestAsync() { @@ -26,12 +33,36 @@ public async Task ItInvokeRightHandlerTestAsync() agent.ReceivedItems[1].Should().Be(42); } + [Fact] + public async Task ItDelegateMessageToTestAgentAsync() + { + var client = _fixture.AppHost.Services.GetRequiredService(); + + await client.PublishMessageAsync(new TextMessage() + { + Source = nameof(ItDelegateMessageToTestAgentAsync), + 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) + { + await Task.Delay(100); + } + + TestAgent.ReceivedMessages[nameof(ItDelegateMessageToTestAgentAsync)].Should().NotBeNull(); + } + /// /// The test agent is a simple agent that is used for testing purposes. /// - public class TestAgent : AgentBase, IHandle, IHandle + public class TestAgent : AgentBase, IHandle, IHandle, IHandle { - public TestAgent(IAgentRuntime context, EventTypes eventTypes, Logger logger) : base(context, eventTypes, logger) + public TestAgent( + IAgentRuntime context, + [FromKeyedServices("EventTypes")] EventTypes eventTypes, + Logger? logger = null) : base(context, eventTypes, logger) { } @@ -47,6 +78,49 @@ public Task Handle(int item) return Task.CompletedTask; } + public Task Handle(TextMessage item) + { + ReceivedMessages[item.Source] = item.TextMessage_; + return Task.CompletedTask; + } + public List ReceivedItems { get; private set; } = []; + + /// + /// Key: source + /// Value: message + /// + public static ConcurrentDictionary ReceivedMessages { get; private set; } = new(); + } +} + +public sealed class InMemoryAgentRuntimeFixture : IDisposable +{ + public InMemoryAgentRuntimeFixture() + { + var builder = Microsoft.Extensions.Hosting.Host.CreateApplicationBuilder(); + + // step 1: create in-memory agent runtime + // step 2: register TestAgent to that agent runtime + builder + .AddAgentService(local: true, useGrpc: false) + .AddAgentWorker(local: true) + .AddAgent(nameof(TestAgent)); + + AppHost = builder.Build(); + AppHost.StartAsync().Wait(); + } + public IHost AppHost { get; } + + void IDisposable.Dispose() + { + AppHost.StopAsync().Wait(); + AppHost.Dispose(); } } + +[CollectionDefinition(Name)] +public sealed class ClusterFixtureCollection : ICollectionFixture +{ + public const string Name = nameof(ClusterFixtureCollection); +} diff --git a/dotnet/test/Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj b/dotnet/test/Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj index db7467bf123..4abf1dc834d 100644 --- a/dotnet/test/Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj +++ b/dotnet/test/Microsoft.AutoGen.Agents.Tests/Microsoft.AutoGen.Agents.Tests.csproj @@ -9,6 +9,7 @@ + diff --git a/dotnet/website/articles/Installation.md b/dotnet/website/articles/Installation.md index 30b55442d24..b421304b04b 100644 --- a/dotnet/website/articles/Installation.md +++ b/dotnet/website/articles/Installation.md @@ -32,9 +32,7 @@ dotnet add package AUTOGEN_PACKAGES ### Consume nightly build To consume nightly build, you can add one of the following feeds to your `NuGet.config` or global nuget config: -- ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/github-grey?style=flat): https://nuget.pkg.github.com/microsoft/index.json -- ![Static Badge](https://img.shields.io/badge/public-blue?style=flat) ![Static Badge](https://img.shields.io/badge/myget-grey?style=flat): https://www.myget.org/F/agentchat/api/v3/index.json -- ![Static Badge](https://img.shields.io/badge/internal-blue?style=flat) ![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat) : https://devdiv.pkgs.visualstudio.com/DevDiv/_packaging/AutoGen/nuget/v3/index.json +> - [![Static Badge](https://img.shields.io/badge/azure_devops-grey?style=flat)](https://dev.azure.com/AGPublish/AGPublic/_artifacts/feed/AutoGen-Nightly) : To add a local `NuGet.config`, create a file named `NuGet.config` in the root of your project and add the following content: ```xml @@ -42,8 +40,6 @@ To add a local `NuGet.config`, create a file named `NuGet.config` in the root of - - diff --git a/dotnet/website/articles/getting-start.md b/dotnet/website/articles/getting-start.md index fe10a597aac..0d4bf331636 100644 --- a/dotnet/website/articles/getting-start.md +++ b/dotnet/website/articles/getting-start.md @@ -1,6 +1,5 @@ ### Get start with AutoGen for dotnet [![dotnet-ci](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml/badge.svg)](https://github.com/microsoft/autogen/actions/workflows/dotnet-build.yml) -[![Discord](https://img.shields.io/discord/1153072414184452236?logo=discord&style=flat)](https://discord.gg/pAbnFJrkgZ) [![NuGet version](https://badge.fury.io/nu/AutoGen.Core.svg)](https://badge.fury.io/nu/AutoGen.Core) Firstly, add `AutoGen` package to your project. diff --git a/dotnet/website/release_note/toc.yml b/dotnet/website/release_note/toc.yml index 6f070c70b86..5a423078ac6 100644 --- a/dotnet/website/release_note/toc.yml +++ b/dotnet/website/release_note/toc.yml @@ -2,7 +2,7 @@ href: 0.2.2.md - name: 0.2.1 -href: 0.2.1.md + href: 0.2.1.md - name: 0.2.0 href: 0.2.0.md @@ -17,4 +17,4 @@ href: 0.2.1.md href: 0.0.16.md - name: 0.0.0 - 0.0.15 - href: update.md \ No newline at end of file + href: update.md