| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
3148bcebf2 | update oai and aoai package version | 1 year ago |
|
|
e5810a3920 | Merge branch 'LittleLittleCloud-patch-1' of https://github.com/microsoft/autogen into LittleLittleCloud-patch-1 | 1 year ago |
|
|
297c1f08fa | fix aot tests | 1 year ago |
|
|
cdaa9b00ad
|
Update dotnet-build.yml | 1 year ago |
|
|
d834d257b5 | fix formatting | 1 year ago |
|
|
1ffb7dc935 | fix whitespace | 1 year ago |
|
|
32c0605a7a | fix IDE warning | 1 year ago |
|
|
0245ab7321
|
Update rollForward to latestFeature in global.json | 1 year ago |
|
|
f20d326942
|
Update dotnet-build.yml | 1 year ago |
|
|
1d4f31041c
|
.NET update global.json to use 9.0.100 | 1 year ago |
| @@ -81,6 +81,10 @@ jobs: | |||||
| uses: actions/setup-dotnet@v4 | uses: actions/setup-dotnet@v4 | ||||
| with: | with: | ||||
| dotnet-version: '8.0.x' | dotnet-version: '8.0.x' | ||||
| - name: Setup .NET 9.0 | |||||
| uses: actions/setup-dotnet@v4 | |||||
| with: | |||||
| dotnet-version: '9.0.x' | |||||
| - name: Restore dependencies | - name: Restore dependencies | ||||
| run: dotnet restore -bl | run: dotnet restore -bl | ||||
| - name: Format check | - name: Format check | ||||
| @@ -207,6 +211,10 @@ jobs: | |||||
| uses: actions/setup-dotnet@v4 | uses: actions/setup-dotnet@v4 | ||||
| with: | with: | ||||
| dotnet-version: '8.0.x' | dotnet-version: '8.0.x' | ||||
| - name: Setup .NET 9.0 | |||||
| uses: actions/setup-dotnet@v4 | |||||
| with: | |||||
| dotnet-version: '9.0.x' | |||||
| - name: publish AOT testApp, assert static analysis warning count, and run the app | - name: publish AOT testApp, assert static analysis warning count, and run the app | ||||
| shell: pwsh | shell: pwsh | ||||
| @@ -249,6 +257,10 @@ jobs: | |||||
| with: | with: | ||||
| dotnet-version: '8.0.x' | dotnet-version: '8.0.x' | ||||
| global-json-file: dotnet/global.json | global-json-file: dotnet/global.json | ||||
| - name: Setup .NET 9.0 | |||||
| uses: actions/setup-dotnet@v4 | |||||
| with: | |||||
| dotnet-version: '9.0.x' | |||||
| - name: Install dev certs | - name: Install dev certs | ||||
| run: dotnet --version && dotnet dev-certs https --trust | run: dotnet --version && dotnet dev-certs https --trust | ||||
| - name: Restore dependencies | - name: Restore dependencies | ||||
| @@ -15,7 +15,7 @@ foreach ($line in $($publishOutput -split "`r`n")) | |||||
| } | } | ||||
| } | } | ||||
| pushd $rootDirectory/artifacts/bin/AutoGen.AotCompatibility.Tests/release | |||||
| pushd $rootDirectory/artifacts/bin/AutoGen.AotCompatibility.Tests/release/native | |||||
| Write-Host "Executing test App..." | Write-Host "Executing test App..." | ||||
| ./AutoGen.AotCompatibility.Tests | ./AutoGen.AotCompatibility.Tests | ||||
| @@ -2,10 +2,12 @@ | |||||
| <PropertyGroup> | <PropertyGroup> | ||||
| <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> | <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally> | ||||
| <MicrosoftSemanticKernelVersion>1.22.0</MicrosoftSemanticKernelVersion> | <MicrosoftSemanticKernelVersion>1.22.0</MicrosoftSemanticKernelVersion> | ||||
| <MicrosoftSemanticKernelExperimentalVersion>1.22.0-alpha</MicrosoftSemanticKernelExperimentalVersion> | |||||
| <MicrosoftExtensionsAIVersion>9.0.0-preview.9.24525.1</MicrosoftExtensionsAIVersion> | |||||
| <MicrosoftSemanticKernelStableVersion>1.45.0</MicrosoftSemanticKernelStableVersion> | |||||
| <MicrosoftSemanticKernelPreviewVersion>$(MicrosoftSemanticKernelStableVersion)-preview</MicrosoftSemanticKernelPreviewVersion> | |||||
| <MicrosoftSemanticKernelAlphaVersion>$(MicrosoftSemanticKernelStableVersion)-alpha</MicrosoftSemanticKernelAlphaVersion> | |||||
| <MicrosoftExtensionsAIVersion>9.3.0-preview.1.25161.3</MicrosoftExtensionsAIVersion> | |||||
| <MicrosoftExtensionConfiguration>9.0.0</MicrosoftExtensionConfiguration> | <MicrosoftExtensionConfiguration>9.0.0</MicrosoftExtensionConfiguration> | ||||
| <MicrosoftExtensionDependencyInjection>9.0.0</MicrosoftExtensionDependencyInjection> | |||||
| <MicrosoftExtensionDependencyInjection>9.0.3</MicrosoftExtensionDependencyInjection> | |||||
| <MicrosoftExtensionLogging>9.0.0</MicrosoftExtensionLogging> | <MicrosoftExtensionLogging>9.0.0</MicrosoftExtensionLogging> | ||||
| <MicrosoftExtensionOptions>9.0.0</MicrosoftExtensionOptions> | <MicrosoftExtensionOptions>9.0.0</MicrosoftExtensionOptions> | ||||
| <MicrosoftOrleans>9.0.1</MicrosoftOrleans> | <MicrosoftOrleans>9.0.1</MicrosoftOrleans> | ||||
| @@ -18,7 +20,7 @@ | |||||
| <PackageVersion Include="Aspire.Hosting" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting" Version="9.0.0" /> | ||||
| <PackageVersion Include="Aspire.Hosting.Python" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting.Python" Version="9.0.0" /> | ||||
| <PackageVersion Include="Aspire.Hosting.Testing" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting.Testing" Version="9.0.0" /> | ||||
| <PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="8.0.1-preview.8.24267.1" /> | |||||
| <PackageVersion Include="Aspire.Azure.AI.OpenAI" Version="9.0.0-preview.5.24551.3" /> | |||||
| <PackageVersion Include="Aspire.Hosting.AppHost" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting.AppHost" Version="9.0.0" /> | ||||
| <PackageVersion Include="Aspire.Hosting.Azure.ApplicationInsights" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting.Azure.ApplicationInsights" Version="9.0.0" /> | ||||
| <PackageVersion Include="Aspire.Hosting.Azure.CognitiveServices" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting.Azure.CognitiveServices" Version="9.0.0" /> | ||||
| @@ -27,9 +29,10 @@ | |||||
| <PackageVersion Include="Aspire.Hosting.Qdrant" Version="9.0.0" /> | <PackageVersion Include="Aspire.Hosting.Qdrant" Version="9.0.0" /> | ||||
| <PackageVersion Include="Aspire.Hosting.Redis" Version="8.2.0" /> | <PackageVersion Include="Aspire.Hosting.Redis" Version="8.2.0" /> | ||||
| <PackageVersion Include="AspNetCore.Authentication.ApiKey" Version="8.0.1" /> | <PackageVersion Include="AspNetCore.Authentication.ApiKey" Version="8.0.1" /> | ||||
| <PackageVersion Include="Azure.AI.OpenAI" Version="2.1.0-beta.2" /> | |||||
| <PackageVersion Include="Azure.AI.OpenAI" Version="2.2.0-beta.4" /> | |||||
| <PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.1" /> | <PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.1" /> | ||||
| <PackageVersion Include="Azure.Data.Tables" Version="12.9.1" /> | <PackageVersion Include="Azure.Data.Tables" Version="12.9.1" /> | ||||
| <PackageVersion Include="Azure.Core" Version="1.44.1" /> | |||||
| <PackageVersion Include="Azure.Identity" Version="1.13.1" /> | <PackageVersion Include="Azure.Identity" Version="1.13.1" /> | ||||
| <PackageVersion Include="Azure.ResourceManager.ContainerInstance" Version="1.2.1" /> | <PackageVersion Include="Azure.ResourceManager.ContainerInstance" Version="1.2.1" /> | ||||
| <PackageVersion Include="Azure.Storage.Files.Shares" Version="12.21.0" /> | <PackageVersion Include="Azure.Storage.Files.Shares" Version="12.21.0" /> | ||||
| @@ -100,18 +103,18 @@ | |||||
| <PackageVersion Include="Microsoft.Orleans.Streaming.EventHubs" Version="$(MicrosoftOrleans)" /> | <PackageVersion Include="Microsoft.Orleans.Streaming.EventHubs" Version="$(MicrosoftOrleans)" /> | ||||
| <PackageVersion Include="Microsoft.Orleans.TestingHost" Version="9.0.1" /> | <PackageVersion Include="Microsoft.Orleans.TestingHost" Version="9.0.1" /> | ||||
| <PackageVersion Include="Microsoft.PowerShell.SDK" Version="7.5.0" /> | <PackageVersion Include="Microsoft.PowerShell.SDK" Version="7.5.0" /> | ||||
| <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" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="$(MicrosoftSemanticKernelExperimentalVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Plugins.Memory" Version="$(MicrosoftSemanticKernelExperimentalVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Plugins.Web" Version="$(MicrosoftSemanticKernelExperimentalVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel" Version="$(MicrosoftSemanticKernelStableVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Agents.Core" Version="$(MicrosoftSemanticKernelStableVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Connectors.AzureOpenAI" Version="$(MicrosoftSemanticKernelStableVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="$(MicrosoftSemanticKernelPreviewVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Plugins.Memory" Version="$(MicrosoftSemanticKernelAlphaVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SemanticKernel.Plugins.Web" Version="$(MicrosoftSemanticKernelAlphaVersion)" /> | |||||
| <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" /> | <PackageVersion Include="Microsoft.SourceLink.GitHub" Version="8.0.0" /> | ||||
| <PackageVersion Include="Moq" Version="4.20.72" /> | <PackageVersion Include="Moq" Version="4.20.72" /> | ||||
| <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> | <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" /> | ||||
| <PackageVersion Include="Octokit" Version="13.0.1" /> | <PackageVersion Include="Octokit" Version="13.0.1" /> | ||||
| <PackageVersion Include="Octokit.Webhooks.AspNetCore" Version="2.4.1" /> | <PackageVersion Include="Octokit.Webhooks.AspNetCore" Version="2.4.1" /> | ||||
| <PackageVersion Include="OpenAI" Version="2.1.0-beta.2" /> | |||||
| <PackageVersion Include="OpenAI" Version="2.2.0-beta.4" /> | |||||
| <PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" /> | <PackageVersion Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.10.0" /> | ||||
| <PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" /> | <PackageVersion Include="OpenTelemetry.Extensions.Hosting" Version="1.10.0" /> | ||||
| <PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="$(OpenTelemetryInstrumentation)" /> | <PackageVersion Include="OpenTelemetry.Instrumentation.AspNetCore" Version="$(OpenTelemetryInstrumentation)" /> | ||||
| @@ -127,7 +130,7 @@ | |||||
| <PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" /> | <PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="8.2.1" /> | ||||
| <PackageVersion Include="System.IO.Packaging" Version="9.0.0" /> | <PackageVersion Include="System.IO.Packaging" Version="9.0.0" /> | ||||
| <PackageVersion Include="System.Memory.Data" Version="9.0.0" /> | <PackageVersion Include="System.Memory.Data" Version="9.0.0" /> | ||||
| <PackageVersion Include="System.Text.Json" Version="9.0.0" /> | |||||
| <PackageVersion Include="System.Text.Json" Version="9.0.3" /> | |||||
| <PackageVersion Include="xunit" Version="2.9.2" /> | <PackageVersion Include="xunit" Version="2.9.2" /> | ||||
| <PackageVersion Include="xunit.runner.console" Version="2.9.2" /> | <PackageVersion Include="xunit.runner.console" Version="2.9.2" /> | ||||
| <PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" /> | <PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" /> | ||||
| @@ -1,6 +1,6 @@ | |||||
| { | { | ||||
| "sdk": { | "sdk": { | ||||
| "version": "8.0.401", | |||||
| "rollForward": "latestMinor" | |||||
| "version": "9.0.100", | |||||
| "rollForward": "latestFeature" | |||||
| } | } | ||||
| } | } | ||||
| @@ -42,8 +42,6 @@ public class Tool_Call_With_Ollama_And_LiteLLM | |||||
| }); | }); | ||||
| #endregion Create_tools | #endregion Create_tools | ||||
| #region Create_Agent | #region Create_Agent | ||||
| var liteLLMUrl = "http://localhost:4000"; | |||||
| // api-key is not required for local server | // api-key is not required for local server | ||||
| // so you can use any string here | // so you can use any string here | ||||
| var openAIClient = new OpenAIClient(new ApiKeyCredential("api-key"), new OpenAIClientOptions | var openAIClient = new OpenAIClient(new ApiKeyCredential("api-key"), new OpenAIClientOptions | ||||
| @@ -59,7 +57,7 @@ public class Tool_Call_With_Ollama_And_LiteLLM | |||||
| .RegisterMiddleware(functionMiddleware) | .RegisterMiddleware(functionMiddleware) | ||||
| .RegisterPrintMessage(); | .RegisterPrintMessage(); | ||||
| var reply = await agent.SendAsync("what's the weather in new york"); | |||||
| await agent.SendAsync("what's the weather in new york"); | |||||
| #endregion Create_Agent | #endregion Create_Agent | ||||
| } | } | ||||
| } | } | ||||
| @@ -40,6 +40,6 @@ public class DummyAgent : IStreamingAgent | |||||
| foreach (var c in reply) | foreach (var c in reply) | ||||
| { | { | ||||
| yield return new TextMessageUpdate(Role.Assistant, c.ToString(), this.Name); | yield return new TextMessageUpdate(Role.Assistant, c.ToString(), this.Name); | ||||
| }; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -4,6 +4,8 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Reflection; | |||||
| using System.Text.Json; | |||||
| using System.Text.Json.Serialization; | using System.Text.Json.Serialization; | ||||
| using Microsoft.Extensions.AI; | using Microsoft.Extensions.AI; | ||||
| @@ -69,36 +71,48 @@ public class FunctionContract | |||||
| /// </summary> | /// </summary> | ||||
| public string? ReturnDescription { get; set; } | public string? ReturnDescription { get; set; } | ||||
| public static implicit operator FunctionContract(AIFunctionMetadata metadata) | |||||
| public static implicit operator FunctionContract(AIFunction function) | |||||
| { | { | ||||
| return new FunctionContract | |||||
| var openapiScheme = function.JsonSchema; | |||||
| var parameters = new List<FunctionParameterContract>(); | |||||
| string[] isRequiredProperties = []; | |||||
| if (openapiScheme.TryGetProperty("required", out var requiredElement)) | |||||
| { | { | ||||
| Namespace = metadata.AdditionalProperties.ContainsKey(NamespaceKey) ? metadata.AdditionalProperties[NamespaceKey] as string : null, | |||||
| ClassName = metadata.AdditionalProperties.ContainsKey(ClassNameKey) ? metadata.AdditionalProperties[ClassNameKey] as string : null, | |||||
| Name = metadata.Name, | |||||
| Description = metadata.Description, | |||||
| Parameters = metadata.Parameters?.Select(p => (FunctionParameterContract)p).ToList(), | |||||
| ReturnType = metadata.ReturnParameter.ParameterType, | |||||
| ReturnDescription = metadata.ReturnParameter.Description, | |||||
| }; | |||||
| } | |||||
| isRequiredProperties = requiredElement.Deserialize<string[]>() ?? []; | |||||
| } | |||||
| public static implicit operator AIFunctionMetadata(FunctionContract contract) | |||||
| { | |||||
| return new AIFunctionMetadata(contract.Name) | |||||
| var parameterList = function.UnderlyingMethod?.GetParameters() ?? Array.Empty<ParameterInfo>(); | |||||
| if (openapiScheme.TryGetProperty("properties", out var propertiesElement)) | |||||
| { | { | ||||
| Description = contract.Description, | |||||
| ReturnParameter = new AIFunctionReturnParameterMetadata() | |||||
| var properties = propertiesElement.Deserialize<Dictionary<string, JsonElement>>() ?? new Dictionary<string, JsonElement>(); | |||||
| foreach (var property in properties) | |||||
| { | { | ||||
| Description = contract.ReturnDescription, | |||||
| ParameterType = contract.ReturnType, | |||||
| }, | |||||
| AdditionalProperties = new Dictionary<string, object?> | |||||
| { | |||||
| [NamespaceKey] = contract.Namespace, | |||||
| [ClassNameKey] = contract.ClassName, | |||||
| }, | |||||
| Parameters = [.. contract.Parameters?.Select(p => (AIFunctionParameterMetadata)p)!], | |||||
| var parameterType = parameterList.FirstOrDefault(p => p.Name == property.Key)?.ParameterType; | |||||
| var parameter = new FunctionParameterContract | |||||
| { | |||||
| Name = property.Key, | |||||
| ParameterType = parameterType, // TODO: Need to get the type from the schema | |||||
| IsRequired = isRequiredProperties.Contains(property.Key), | |||||
| }; | |||||
| if (property.Value.TryGetProperty("description", out var descriptionElement)) | |||||
| { | |||||
| parameter.Description = descriptionElement.GetString(); | |||||
| } | |||||
| if (property.Value.TryGetProperty("default", out var defaultValueElement)) | |||||
| { | |||||
| parameter.DefaultValue = defaultValueElement.Deserialize<object>(); | |||||
| } | |||||
| parameters.Add(parameter); | |||||
| } | |||||
| } | |||||
| return new FunctionContract | |||||
| { | |||||
| Namespace = function.AdditionalProperties.ContainsKey(NamespaceKey) ? function.AdditionalProperties[NamespaceKey] as string : null, | |||||
| ClassName = function.AdditionalProperties.ContainsKey(ClassNameKey) ? function.AdditionalProperties[ClassNameKey] as string : null, | |||||
| Name = function.Name, | |||||
| Description = function.Description, | |||||
| Parameters = parameters, | |||||
| }; | }; | ||||
| } | } | ||||
| } | } | ||||
| @@ -132,29 +146,4 @@ public class FunctionParameterContract | |||||
| /// The default value of the parameter. | /// The default value of the parameter. | ||||
| /// </summary> | /// </summary> | ||||
| public object? DefaultValue { get; set; } | public object? DefaultValue { get; set; } | ||||
| // convert to/from FunctionParameterMetadata | |||||
| public static implicit operator FunctionParameterContract(AIFunctionParameterMetadata metadata) | |||||
| { | |||||
| return new FunctionParameterContract | |||||
| { | |||||
| Name = metadata.Name, | |||||
| Description = metadata.Description, | |||||
| ParameterType = metadata.ParameterType, | |||||
| IsRequired = metadata.IsRequired, | |||||
| DefaultValue = metadata.DefaultValue, | |||||
| }; | |||||
| } | |||||
| public static implicit operator AIFunctionParameterMetadata(FunctionParameterContract contract) | |||||
| { | |||||
| return new AIFunctionParameterMetadata(contract.Name!) | |||||
| { | |||||
| DefaultValue = contract.DefaultValue, | |||||
| Description = contract.Description, | |||||
| IsRequired = contract.IsRequired, | |||||
| ParameterType = contract.ParameterType, | |||||
| HasDefaultValue = contract.DefaultValue != null, | |||||
| }; | |||||
| } | |||||
| } | } | ||||
| @@ -53,9 +53,9 @@ public class FunctionCallMiddleware : IStreamingMiddleware | |||||
| public FunctionCallMiddleware(IEnumerable<AIFunction> functions, string? name = null) | public FunctionCallMiddleware(IEnumerable<AIFunction> functions, string? name = null) | ||||
| { | { | ||||
| this.Name = name ?? nameof(FunctionCallMiddleware); | this.Name = name ?? nameof(FunctionCallMiddleware); | ||||
| this.functions = functions.Select(f => (FunctionContract)f.Metadata).ToArray(); | |||||
| this.functions = functions.Select(f => (FunctionContract)f).ToArray(); | |||||
| this.functionMap = functions.Select(f => (f.Metadata.Name, this.AIToolInvokeWrapper(f.InvokeAsync))).ToDictionary(f => f.Name, f => f.Item2); | |||||
| this.functionMap = functions.Select(f => (f.Name, this.AIToolInvokeWrapper(f.InvokeAsync))).ToDictionary(f => f.Name, f => f.Item2); | |||||
| } | } | ||||
| public string? Name { get; } | public string? Name { get; } | ||||
| @@ -26,8 +26,9 @@ public class SemanticKernelChatCompletionAgent : IAgent | |||||
| public async Task<IMessage> GenerateReplyAsync(IEnumerable<IMessage> messages, GenerateReplyOptions? options = null, | public async Task<IMessage> GenerateReplyAsync(IEnumerable<IMessage> messages, GenerateReplyOptions? options = null, | ||||
| CancellationToken cancellationToken = default) | CancellationToken cancellationToken = default) | ||||
| { | { | ||||
| ChatMessageContent[] reply = await _chatCompletionAgent | |||||
| .InvokeAsync(BuildChatHistory(messages), cancellationToken: cancellationToken) | |||||
| var agentThread = new ChatHistoryAgentThread(BuildChatHistory(messages)); | |||||
| var reply = await _chatCompletionAgent | |||||
| .InvokeAsync(agentThread, cancellationToken: cancellationToken) | |||||
| .ToArrayAsync(cancellationToken: cancellationToken); | .ToArrayAsync(cancellationToken: cancellationToken); | ||||
| return reply.Length > 1 | return reply.Length > 1 | ||||
| @@ -170,24 +170,23 @@ public interface IChatAgent : | |||||
| /// <summary> | /// <summary> | ||||
| /// The name of the agent. This is used by team to uniquely identify the agent.It should be unique within the team. | /// The name of the agent. This is used by team to uniquely identify the agent.It should be unique within the team. | ||||
| /// </summary> | /// </summary> | ||||
| AgentName Name { get; } | |||||
| public AgentName Name { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// The description of the agent. This is used by team to make decisions about which agents to use.The description | /// The description of the agent. This is used by team to make decisions about which agents to use.The description | ||||
| /// should describe the agent's capabilities and how to interact with it. | /// should describe the agent's capabilities and how to interact with it. | ||||
| /// </summary> | /// </summary> | ||||
| string Description { get; } | |||||
| public string Description { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// The types of messages that the agent produces. | /// The types of messages that the agent produces. | ||||
| /// </summary> | /// </summary> | ||||
| IEnumerable<Type> ProducedMessageTypes { get; } // TODO: Is there a way to make this part of the type somehow? | |||||
| // Annotations, or IProduce<>? Do we ever actually access this? | |||||
| public IEnumerable<Type> ProducedMessageTypes { get; } // TODO: Is there a way to make this part of the type somehow? Annotations, or IProduce<>? Do we ever actually access this? | |||||
| /// <summary> | /// <summary> | ||||
| /// Reset the agent to its initialization state. | /// Reset the agent to its initialization state. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="cancellationToken"></param> | /// <param name="cancellationToken"></param> | ||||
| /// <returns></returns> | /// <returns></returns> | ||||
| ValueTask ResetAsync(CancellationToken cancellationToken); | |||||
| public ValueTask ResetAsync(CancellationToken cancellationToken); | |||||
| } | } | ||||
| @@ -5,22 +5,22 @@ namespace Microsoft.AutoGen.AgentChat.Abstractions; | |||||
| public interface IHandleChat<in TIn> | public interface IHandleChat<in TIn> | ||||
| { | { | ||||
| ValueTask HandleAsync(TIn item) | |||||
| public ValueTask HandleAsync(TIn item) | |||||
| { | { | ||||
| return this.HandleAsync(item, CancellationToken.None); | return this.HandleAsync(item, CancellationToken.None); | ||||
| } | } | ||||
| ValueTask HandleAsync(TIn item, CancellationToken cancellationToken); | |||||
| public ValueTask HandleAsync(TIn item, CancellationToken cancellationToken); | |||||
| } | } | ||||
| public interface IHandleChat<in TIn, TOut> // TODO: Map this to IHandle<> somehow? | public interface IHandleChat<in TIn, TOut> // TODO: Map this to IHandle<> somehow? | ||||
| { | { | ||||
| ValueTask<TOut> HandleAsync(TIn item) | |||||
| public ValueTask<TOut> HandleAsync(TIn item) | |||||
| { | { | ||||
| return this.HandleAsync(item, CancellationToken.None); | return this.HandleAsync(item, CancellationToken.None); | ||||
| } | } | ||||
| ValueTask<TOut> HandleAsync(TIn item, CancellationToken cancellationToken); | |||||
| public ValueTask<TOut> HandleAsync(TIn item, CancellationToken cancellationToken); | |||||
| } | } | ||||
| public interface IHandleDefault : IHandleChat<object> | public interface IHandleDefault : IHandleChat<object> | ||||
| @@ -29,10 +29,10 @@ public interface IHandleDefault : IHandleChat<object> | |||||
| public interface IHandleStream<in TIn, TOut> | public interface IHandleStream<in TIn, TOut> | ||||
| { | { | ||||
| IAsyncEnumerable<TOut> StreamAsync(TIn item) | |||||
| public IAsyncEnumerable<TOut> StreamAsync(TIn item) | |||||
| { | { | ||||
| return this.StreamAsync(item, CancellationToken.None); | return this.StreamAsync(item, CancellationToken.None); | ||||
| } | } | ||||
| IAsyncEnumerable<TOut> StreamAsync(TIn item, CancellationToken cancellationToken); | |||||
| public IAsyncEnumerable<TOut> StreamAsync(TIn item, CancellationToken cancellationToken); | |||||
| } | } | ||||
| @@ -116,7 +116,7 @@ public struct MultiModalData | |||||
| /// <param name="item">The <see cref="AIContent"/> to wrap.</param> | /// <param name="item">The <see cref="AIContent"/> to wrap.</param> | ||||
| /// <returns>A <see cref="MultiModalData"/> instance wrapping the <paramref name="item"/>.</returns> | /// <returns>A <see cref="MultiModalData"/> instance wrapping the <paramref name="item"/>.</returns> | ||||
| /// <exception cref="ArgumentException"> | /// <exception cref="ArgumentException"> | ||||
| /// Thrown if the <paramref name="item"/> is not a <see cref="TextContent"/> or <see cref="ImageContent"/>. | |||||
| /// Thrown if the <paramref name="item"/> is not a <see cref="TextContent"/> or <see cref="DataContent"/>. | |||||
| /// </exception> | /// </exception> | ||||
| public static MultiModalData CheckTypeAndCreate(AIContent item) | public static MultiModalData CheckTypeAndCreate(AIContent item) | ||||
| { | { | ||||
| @@ -124,7 +124,7 @@ public struct MultiModalData | |||||
| { | { | ||||
| return new MultiModalData(text); | return new MultiModalData(text); | ||||
| } | } | ||||
| else if (item is ImageContent image) | |||||
| else if (item is DataContent image) | |||||
| { | { | ||||
| return new MultiModalData(image); | return new MultiModalData(image); | ||||
| } | } | ||||
| @@ -155,10 +155,10 @@ public struct MultiModalData | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Initializes a new instance of the <see cref="MultiModalData"/> with an <see cref="ImageContent"/>. | |||||
| /// Initializes a new instance of the <see cref="MultiModalData"/> with an <see cref="DataContent"/>. | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="image">The image to wrap.</param> | /// <param name="image">The image to wrap.</param> | ||||
| public MultiModalData(ImageContent image) | |||||
| public MultiModalData(DataContent image) | |||||
| { | { | ||||
| ContentType = Type.Image; | ContentType = Type.Image; | ||||
| AIContent = image; | AIContent = image; | ||||
| @@ -246,12 +246,12 @@ public class MultiModalMessage : ChatMessage, IList<AIContent> | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| /// Adds a range of <see cref="ImageContent"/> to the message. | |||||
| /// Adds a range of <see cref="DataContent"/> to the message. | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="images">The items to add.</param> | /// <param name="images">The items to add.</param> | ||||
| public void AddRange(IEnumerable<ImageContent> images) | |||||
| public void AddRange(IEnumerable<DataContent> images) | |||||
| { | { | ||||
| foreach (ImageContent image in images) | |||||
| foreach (DataContent image in images) | |||||
| { | { | ||||
| this.Add(image); | this.Add(image); | ||||
| } | } | ||||
| @@ -279,7 +279,7 @@ public class MultiModalMessage : ChatMessage, IList<AIContent> | |||||
| /// Adds a <see cref="TextContent"/> to the message. | /// Adds a <see cref="TextContent"/> to the message. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="image">The image to add.</param> | /// <param name="image">The image to add.</param> | ||||
| public void Add(ImageContent image) | |||||
| public void Add(DataContent image) | |||||
| { | { | ||||
| this.Content.Add(new(image)); | this.Content.Add(new(image)); | ||||
| } | } | ||||
| @@ -366,7 +366,7 @@ public class MultiModalMessage : ChatMessage, IList<AIContent> | |||||
| } | } | ||||
| /// <inheritdoc cref="IList{ImageContent}.Insert(int, ImageContent)"/> | /// <inheritdoc cref="IList{ImageContent}.Insert(int, ImageContent)"/> | ||||
| public void Insert(int index, ImageContent image) | |||||
| public void Insert(int index, DataContent image) | |||||
| { | { | ||||
| this.Content.Insert(index, new(image)); | this.Content.Insert(index, new(image)); | ||||
| } | } | ||||
| @@ -597,7 +597,7 @@ public static class CompletionChatMessageExtensions | |||||
| { | { | ||||
| contentBuilder.AppendLine(textContent.Text); | contentBuilder.AppendLine(textContent.Text); | ||||
| } | } | ||||
| else if (content is ImageContent) | |||||
| else if (content is DataContent) | |||||
| { | { | ||||
| contentBuilder.AppendLine("[Image]"); | contentBuilder.AppendLine("[Image]"); | ||||
| } | } | ||||
| @@ -59,7 +59,7 @@ public interface ITaskRunner | |||||
| /// <param name="task">The task definition in text form.</param> | /// <param name="task">The task definition in text form.</param> | ||||
| /// <param name="cancellationToken"></param> | /// <param name="cancellationToken"></param> | ||||
| /// <returns>The result of running the task.</returns> | /// <returns>The result of running the task.</returns> | ||||
| async ValueTask<TaskResult> RunAsync(string task, CancellationToken cancellationToken = default) => | |||||
| public async ValueTask<TaskResult> RunAsync(string task, CancellationToken cancellationToken = default) => | |||||
| await this.RunAsync(ToMessage(task)!, cancellationToken); | await this.RunAsync(ToMessage(task)!, cancellationToken); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -73,7 +73,7 @@ public interface ITaskRunner | |||||
| /// <param name="cancellationToken"></param> | /// <param name="cancellationToken"></param> | ||||
| /// <returns>The result of running the task.</returns> | /// <returns>The result of running the task.</returns> | ||||
| /// <exception cref="InvalidOperationException">If no response is generated.</exception> | /// <exception cref="InvalidOperationException">If no response is generated.</exception> | ||||
| async ValueTask<TaskResult> RunAsync(ChatMessage task, CancellationToken cancellationToken = default) | |||||
| public async ValueTask<TaskResult> RunAsync(ChatMessage task, CancellationToken cancellationToken = default) | |||||
| { | { | ||||
| await foreach (TaskFrame frame in this.StreamAsync(task, cancellationToken)) | await foreach (TaskFrame frame in this.StreamAsync(task, cancellationToken)) | ||||
| { | { | ||||
| @@ -98,7 +98,7 @@ public interface ITaskRunner | |||||
| /// <param name="cancellationToken"></param> | /// <param name="cancellationToken"></param> | ||||
| /// <returns>A stream of <see cref="TaskFrame"/> containing internal messages and intermediate results followed by | /// <returns>A stream of <see cref="TaskFrame"/> containing internal messages and intermediate results followed by | ||||
| /// the final <see cref="TaskResult"/></returns> | /// the final <see cref="TaskResult"/></returns> | ||||
| IAsyncEnumerable<TaskFrame> StreamAsync(string task, CancellationToken cancellationToken = default) => | |||||
| public IAsyncEnumerable<TaskFrame> StreamAsync(string task, CancellationToken cancellationToken = default) => | |||||
| this.StreamAsync(ToMessage(task), cancellationToken); | this.StreamAsync(ToMessage(task), cancellationToken); | ||||
| /// <summary> | /// <summary> | ||||
| @@ -113,5 +113,5 @@ public interface ITaskRunner | |||||
| /// <param name="cancellationToken"></param> | /// <param name="cancellationToken"></param> | ||||
| /// <returns>A stream of <see cref="TaskFrame"/> containing internal messages and intermediate results followed by | /// <returns>A stream of <see cref="TaskFrame"/> containing internal messages and intermediate results followed by | ||||
| /// the final <see cref="TaskResult"/></returns> | /// the final <see cref="TaskResult"/></returns> | ||||
| IAsyncEnumerable<TaskFrame> StreamAsync(ChatMessage? task, CancellationToken cancellationToken = default); | |||||
| public IAsyncEnumerable<TaskFrame> StreamAsync(ChatMessage? task, CancellationToken cancellationToken = default); | |||||
| } | } | ||||
| @@ -19,7 +19,7 @@ public interface ITerminationCondition | |||||
| /// <summary> | /// <summary> | ||||
| /// Checks if the termination condition has been reached | /// Checks if the termination condition has been reached | ||||
| /// </summary> | /// </summary> | ||||
| bool IsTerminated { get; } | |||||
| public bool IsTerminated { get; } | |||||
| /// <summary> | /// <summary> | ||||
| /// Check if the conversation should be terminated based on the messages received | /// Check if the conversation should be terminated based on the messages received | ||||
| @@ -30,19 +30,19 @@ public interface ITerminationCondition | |||||
| /// <returns>A <see cref="StopMessage"/> if the conversation should be terminated, or <c>null</c> | /// <returns>A <see cref="StopMessage"/> if the conversation should be terminated, or <c>null</c> | ||||
| /// otherwise.</returns> | /// otherwise.</returns> | ||||
| /// <exception cref="TerminatedException">If the termination condition has already been reached.</exception> | /// <exception cref="TerminatedException">If the termination condition has already been reached.</exception> | ||||
| ValueTask<StopMessage?> CheckAndUpdateAsync(IList<AgentMessage> messages); | |||||
| public ValueTask<StopMessage?> CheckAndUpdateAsync(IList<AgentMessage> messages); | |||||
| /// <summary> | /// <summary> | ||||
| /// Resets the termination condition. | /// Resets the termination condition. | ||||
| /// </summary> | /// </summary> | ||||
| void Reset(); | |||||
| public void Reset(); | |||||
| /// <summary> | /// <summary> | ||||
| /// Combine this termination condition with another using a logical OR. | /// Combine this termination condition with another using a logical OR. | ||||
| /// </summary> | /// </summary> | ||||
| /// <param name="other">Another termination condition.</param> | /// <param name="other">Another termination condition.</param> | ||||
| /// <returns>The combined termination condition, with appropriate short-circuiting.</returns> | /// <returns>The combined termination condition, with appropriate short-circuiting.</returns> | ||||
| ITerminationCondition Or(ITerminationCondition other) | |||||
| public ITerminationCondition Or(ITerminationCondition other) | |||||
| { | { | ||||
| return new CombinerCondition(CombinerCondition.Or, this, other); | return new CombinerCondition(CombinerCondition.Or, this, other); | ||||
| } | } | ||||
| @@ -52,7 +52,7 @@ public interface ITerminationCondition | |||||
| /// </summary> | /// </summary> | ||||
| /// <param name="other">Another termination condition.</param> | /// <param name="other">Another termination condition.</param> | ||||
| /// <returns>The combined termination condition, with appropriate short-circuiting.</returns> | /// <returns>The combined termination condition, with appropriate short-circuiting.</returns> | ||||
| ITerminationCondition And(ITerminationCondition other) | |||||
| public ITerminationCondition And(ITerminationCondition other) | |||||
| { | { | ||||
| return new CombinerCondition(CombinerCondition.And, this, other); | return new CombinerCondition(CombinerCondition.And, this, other); | ||||
| } | } | ||||
| @@ -1,7 +1,6 @@ | |||||
| // Copyright (c) Microsoft Corporation. All rights reserved. | // Copyright (c) Microsoft Corporation. All rights reserved. | ||||
| // Tools.cs | // Tools.cs | ||||
| using System.ComponentModel; | |||||
| using System.Reflection; | using System.Reflection; | ||||
| using Microsoft.Extensions.AI; | using Microsoft.Extensions.AI; | ||||
| @@ -10,37 +9,6 @@ namespace Microsoft.AutoGen.AgentChat.Abstractions; | |||||
| // TODO: This likely should live as a "Component" in an Agent-building ClassLib? | // TODO: This likely should live as a "Component" in an Agent-building ClassLib? | ||||
| // It seems like it could have applicability beyond AgentChat. | // It seems like it could have applicability beyond AgentChat. | ||||
| public static class ReflectionExtensions | |||||
| { | |||||
| public static AIFunctionParameterMetadata ToAIFunctionMetadata(this ParameterInfo pi) | |||||
| { | |||||
| return new AIFunctionParameterMetadata(pi.Name!) | |||||
| { | |||||
| Description = pi.GetCustomAttribute<DescriptionAttribute>()?.Description, | |||||
| ParameterType = pi.ParameterType, | |||||
| HasDefaultValue = pi.HasDefaultValue, | |||||
| IsRequired = !pi.HasDefaultValue, | |||||
| DefaultValue = pi.DefaultValue, | |||||
| // Schema = JSONSchema of type | |||||
| }; | |||||
| } | |||||
| public static AIFunctionReturnParameterMetadata ToAIFunctionReturnMetadata(this ParameterInfo rpi) | |||||
| { | |||||
| return new AIFunctionReturnParameterMetadata | |||||
| { | |||||
| Description = rpi.GetCustomAttribute<DescriptionAttribute>()?.Description, | |||||
| ParameterType = rpi.ParameterType | |||||
| //Schema = JSONSchema of type | |||||
| }; | |||||
| } | |||||
| } | |||||
| public class ParameterSchema(string name, Type type, bool isRequired = false, object? defaultValue = default) | public class ParameterSchema(string name, Type type, bool isRequired = false, object? defaultValue = default) | ||||
| { | { | ||||
| public string Name { get; } = name; | public string Name { get; } = name; | ||||
| @@ -54,15 +22,6 @@ public class ParameterSchema(string name, Type type, bool isRequired = false, ob | |||||
| Type parameterType = parameterInfo.ParameterType; | Type parameterType = parameterInfo.ParameterType; | ||||
| return ParameterSchema<object>.Create(parameterType, parameterInfo.Name!, parameterInfo.HasDefaultValue, parameterInfo.DefaultValue); | return ParameterSchema<object>.Create(parameterType, parameterInfo.Name!, parameterInfo.HasDefaultValue, parameterInfo.DefaultValue); | ||||
| } | } | ||||
| public static implicit operator ParameterSchema(AIFunctionParameterMetadata parameterMetadata) | |||||
| { | |||||
| Type parameterType = parameterMetadata.ParameterType!; // TODO: Deal with missing ParameterTypes | |||||
| return ParameterSchema<object>.Create(parameterType, | |||||
| parameterMetadata.Name, | |||||
| parameterMetadata.IsRequired, | |||||
| parameterMetadata.DefaultValue); | |||||
| } | |||||
| } | } | ||||
| // TODO: Can this be obviated by AIFunctionParameter? | // TODO: Can this be obviated by AIFunctionParameter? | ||||
| @@ -82,11 +41,10 @@ public class ParameterSchema<T>(string name, bool isRequired = false, T? default | |||||
| /// </summary> | /// </summary> | ||||
| public interface ITool | public interface ITool | ||||
| { | { | ||||
| string Name { get; } | |||||
| string Description { get; } | |||||
| public string Name { get; } | |||||
| public string Description { get; } | |||||
| public IEnumerable<ParameterSchema> Parameters { get; } | public IEnumerable<ParameterSchema> Parameters { get; } | ||||
| public Type ReturnType { get; } | |||||
| // TODO: State serialization | // TODO: State serialization | ||||
| @@ -136,18 +94,15 @@ public class AIFunctionTool(AIFunction aiFunction) : ITool | |||||
| public AIFunction AIFunction { get; } = aiFunction; | public AIFunction AIFunction { get; } = aiFunction; | ||||
| /// <inheritdoc cref="ITool.Name" /> | /// <inheritdoc cref="ITool.Name" /> | ||||
| public string Name => this.AIFunction.Metadata.Name; | |||||
| public string Name => this.AIFunction.Name; | |||||
| /// <inheritdoc cref="ITool.Description" /> | /// <inheritdoc cref="ITool.Description" /> | ||||
| public string Description => this.AIFunction.Metadata.Description; | |||||
| public string Description => this.AIFunction.Description; | |||||
| /// <inheritdoc cref="ITool.Parameters" /> | /// <inheritdoc cref="ITool.Parameters" /> | ||||
| public IEnumerable<ParameterSchema> Parameters => from rawParameter in this.AIFunction.Metadata.Parameters | |||||
| public IEnumerable<ParameterSchema> Parameters => from rawParameter in this.AIFunction.UnderlyingMethod!.GetParameters() | |||||
| select (ParameterSchema)rawParameter; | select (ParameterSchema)rawParameter; | ||||
| /// <inheritdoc cref="ITool.ReturnType" /> | |||||
| public Type ReturnType => this.AIFunction.Metadata.ReturnParameter.ParameterType!; // TODO: Deal with missing return types | |||||
| /// <inheritdoc cref="ITool.ExecuteAsync" /> | /// <inheritdoc cref="ITool.ExecuteAsync" /> | ||||
| public Task<object> ExecuteAsync(IEnumerable<object> parameters, CancellationToken cancellationToken = default) | public Task<object> ExecuteAsync(IEnumerable<object> parameters, CancellationToken cancellationToken = default) | ||||
| => this.ExecuteAsync(parameters, cancellationToken); | => this.ExecuteAsync(parameters, cancellationToken); | ||||
| @@ -164,23 +119,6 @@ public class CallableTool(string name, string description, Delegate callable) | |||||
| { | { | ||||
| internal static AIFunction CreateAIFunction(string name, string description, Delegate callable) | internal static AIFunction CreateAIFunction(string name, string description, Delegate callable) | ||||
| { | { | ||||
| MethodInfo methodInfo = callable.Method; | |||||
| IEnumerable<AIFunctionParameterMetadata> parameters = | |||||
| from parameterInfo in methodInfo.GetParameters() | |||||
| select parameterInfo.ToAIFunctionMetadata(); | |||||
| AIFunctionReturnParameterMetadata returnParameter = methodInfo.ReturnParameter.ToAIFunctionReturnMetadata(); | |||||
| AIFunctionFactoryCreateOptions createOptions = new() | |||||
| { | |||||
| Name = name, | |||||
| Description = description, | |||||
| Parameters = parameters.ToList(), | |||||
| ReturnParameter = returnParameter, | |||||
| // SerializerOptions = TODO: How do we maintain consistency with Python? | |||||
| }; | |||||
| return AIFunctionFactory.Create(callable, createOptions); | |||||
| return AIFunctionFactory.Create(callable, name: name, description: description); | |||||
| } | } | ||||
| } | } | ||||
| @@ -114,7 +114,7 @@ public abstract class GroupChatBase<TManager> : ITeam where TManager : GroupChat | |||||
| if (Activator.CreateInstance(typeof(TManager), options) is TManager result) | if (Activator.CreateInstance(typeof(TManager), options) is TManager result) | ||||
| { | { | ||||
| return result; | return result; | ||||
| }; | |||||
| } | |||||
| } | } | ||||
| catch (TargetInvocationException tie) | catch (TargetInvocationException tie) | ||||
| { | { | ||||
| @@ -11,8 +11,8 @@ internal delegate ValueTask MessagePublishServicer(GroupChatEventBase event_, st | |||||
| internal interface IGroupChatHandler : IHandle<GroupChatStart>, IHandle<GroupChatAgentResponse>, IHandle<object> | internal interface IGroupChatHandler : IHandle<GroupChatStart>, IHandle<GroupChatAgentResponse>, IHandle<object> | ||||
| { | { | ||||
| void AttachMessagePublishServicer(MessagePublishServicer? servicer = null); | |||||
| void DetachMessagePublishServicer() => this.AttachMessagePublishServicer(null); | |||||
| public void AttachMessagePublishServicer(MessagePublishServicer? servicer = null); | |||||
| public void DetachMessagePublishServicer() => this.AttachMessagePublishServicer(null); | |||||
| } | } | ||||
| internal sealed class GroupChatHandlerRouter<TManager> : HostableAgentAdapter, | internal sealed class GroupChatHandlerRouter<TManager> : HostableAgentAdapter, | ||||
| @@ -11,8 +11,8 @@ namespace Microsoft.AutoGen.AgentChat.Abstractions; | |||||
| internal interface IOutputCollectionSink | internal interface IOutputCollectionSink | ||||
| { | { | ||||
| void CollectMessage(AgentMessage message); | |||||
| void Terminate(StopMessage message); | |||||
| public void CollectMessage(AgentMessage message); | |||||
| public void Terminate(StopMessage message); | |||||
| } | } | ||||
| internal sealed class OutputSink : IOutputCollectionSink | internal sealed class OutputSink : IOutputCollectionSink | ||||
| @@ -26,19 +26,19 @@ public abstract class InferenceAgent<T>( | |||||
| { | { | ||||
| protected IChatClient ChatClient { get; } = client; | protected IChatClient ChatClient { get; } = client; | ||||
| private ILogger<InferenceAgent<T>>? Logger => _logger as ILogger<InferenceAgent<T>>; | private ILogger<InferenceAgent<T>>? Logger => _logger as ILogger<InferenceAgent<T>>; | ||||
| private Task<ChatCompletion> CompleteAsync( | |||||
| private Task<ChatResponse> CompleteAsync( | |||||
| IList<ChatMessage> chatMessages, | IList<ChatMessage> chatMessages, | ||||
| ChatOptions? options = null, | ChatOptions? options = null, | ||||
| CancellationToken cancellationToken = default) | CancellationToken cancellationToken = default) | ||||
| { | { | ||||
| return ChatClient.CompleteAsync(chatMessages, options, cancellationToken); | |||||
| return ChatClient.GetResponseAsync(chatMessages, options, cancellationToken); | |||||
| } | } | ||||
| private IAsyncEnumerable<StreamingChatCompletionUpdate> CompleteStreamingAsync( | |||||
| private IAsyncEnumerable<ChatResponseUpdate> CompleteStreamingAsync( | |||||
| IList<ChatMessage> chatMessages, | IList<ChatMessage> chatMessages, | ||||
| ChatOptions? options = null, | ChatOptions? options = null, | ||||
| CancellationToken cancellationToken = default) | CancellationToken cancellationToken = default) | ||||
| { | { | ||||
| return ChatClient.CompleteStreamingAsync(chatMessages, options, cancellationToken); | |||||
| return ChatClient.GetStreamingResponseAsync(chatMessages, options, cancellationToken); | |||||
| } | } | ||||
| } | } | ||||
| @@ -43,7 +43,7 @@ internal sealed class AutoRestartChannel : IDisposable | |||||
| if (this.RecreateChannel(null) == null) | if (this.RecreateChannel(null) == null) | ||||
| { | { | ||||
| throw new Exception("Failed to connect to gRPC endpoint."); | throw new Exception("Failed to connect to gRPC endpoint."); | ||||
| }; | |||||
| } | |||||
| } | } | ||||
| public AsyncDuplexStreamingCall<Message, Message> StreamingCall | public AsyncDuplexStreamingCall<Message, Message> StreamingCall | ||||
| @@ -117,8 +117,9 @@ internal sealed class GrpcMessageRouter(AgentRpc.AgentRpcClient client, | |||||
| private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(shutdownCancellation); | private readonly CancellationTokenSource _shutdownCts = CancellationTokenSource.CreateLinkedTokenSource(shutdownCancellation); | ||||
| private readonly IMessageSink<Message> _incomingMessageSink = incomingMessageSink; | private readonly IMessageSink<Message> _incomingMessageSink = incomingMessageSink; | ||||
| // TODO: Enable a way to configure the channel options | |||||
| private readonly Channel<(Message Message, TaskCompletionSource WriteCompletionSource)> _outboundMessagesChannel | private readonly Channel<(Message Message, TaskCompletionSource WriteCompletionSource)> _outboundMessagesChannel | ||||
| // TODO: Enable a way to configure the channel options | |||||
| = Channel.CreateBounded<(Message, TaskCompletionSource)>(DefaultChannelOptions); | = Channel.CreateBounded<(Message, TaskCompletionSource)>(DefaultChannelOptions); | ||||
| private readonly AutoRestartChannel _incomingMessageChannel = new AutoRestartChannel(client, clientId, logger, shutdownCancellation); | private readonly AutoRestartChannel _incomingMessageChannel = new AutoRestartChannel(client, clientId, logger, shutdownCancellation); | ||||
| @@ -7,11 +7,11 @@ namespace Microsoft.AutoGen.Core; | |||||
| internal interface IResultSink<TResult> : IValueTaskSource<TResult> | internal interface IResultSink<TResult> : IValueTaskSource<TResult> | ||||
| { | { | ||||
| void SetResult(TResult result); | |||||
| void SetException(Exception exception); | |||||
| void SetCancelled(); | |||||
| public void SetResult(TResult result); | |||||
| public void SetException(Exception exception); | |||||
| public void SetCancelled(); | |||||
| ValueTask<TResult> Future { get; } | |||||
| public ValueTask<TResult> Future { get; } | |||||
| } | } | ||||
| public sealed class ResultSink<TResult> : IResultSink<TResult> | public sealed class ResultSink<TResult> : IResultSink<TResult> | ||||
| @@ -41,12 +41,13 @@ public static class ServiceCollectionChatClientExtensions | |||||
| Func<ChatClientBuilder, ChatClientBuilder>? builder = null) | Func<ChatClientBuilder, ChatClientBuilder>? builder = null) | ||||
| { | { | ||||
| uri ??= new Uri("http://localhost:11434"); | uri ??= new Uri("http://localhost:11434"); | ||||
| return services.AddChatClient(pipeline => | |||||
| services.AddChatClient(service => | |||||
| { | { | ||||
| builder?.Invoke(pipeline); | |||||
| var httpClient = pipeline.Services.GetService<HttpClient>() ?? new(); | |||||
| return pipeline.Use(new OllamaChatClient(uri, modelName, httpClient)); | |||||
| var httpClient = service.GetService<HttpClient>() ?? new(); | |||||
| return new OllamaChatClient(uri, modelName, httpClient); | |||||
| }); | }); | ||||
| return services; | |||||
| } | } | ||||
| public static IServiceCollection AddOpenAIChatClient( | public static IServiceCollection AddOpenAIChatClient( | ||||
| this IHostApplicationBuilder hostBuilder, | this IHostApplicationBuilder hostBuilder, | ||||
| @@ -81,16 +82,17 @@ public static class ServiceCollectionChatClientExtensions | |||||
| Uri? endpoint = null, | Uri? endpoint = null, | ||||
| Func<ChatClientBuilder, ChatClientBuilder>? builder = null) | Func<ChatClientBuilder, ChatClientBuilder>? builder = null) | ||||
| { | { | ||||
| return services | |||||
| services | |||||
| .AddSingleton(_ => endpoint is null | .AddSingleton(_ => endpoint is null | ||||
| ? new OpenAIClient(apiKey) | ? new OpenAIClient(apiKey) | ||||
| : new AzureOpenAIClient(endpoint, new ApiKeyCredential(apiKey))) | : new AzureOpenAIClient(endpoint, new ApiKeyCredential(apiKey))) | ||||
| .AddChatClient(pipeline => | |||||
| .AddChatClient(service => | |||||
| { | { | ||||
| builder?.Invoke(pipeline); | |||||
| var openAiClient = pipeline.Services.GetRequiredService<OpenAIClient>(); | |||||
| return pipeline.Use(openAiClient.AsChatClient(modelOrDeploymentName)); | |||||
| var openAiClient = service.GetRequiredService<OpenAIClient>(); | |||||
| return openAiClient.AsChatClient(modelOrDeploymentName); | |||||
| }); | }); | ||||
| return services; | |||||
| } | } | ||||
| public static IServiceCollection AddAzureChatClient( | public static IServiceCollection AddAzureChatClient( | ||||
| this IHostApplicationBuilder hostBuilder, | this IHostApplicationBuilder hostBuilder, | ||||
| @@ -109,12 +111,10 @@ public static class ServiceCollectionChatClientExtensions | |||||
| } | } | ||||
| var endpoint = $"{serviceName}:Endpoint" ?? throw new InvalidOperationException($"No endpoint was specified for the Azure Inference Chat Client"); | var endpoint = $"{serviceName}:Endpoint" ?? throw new InvalidOperationException($"No endpoint was specified for the Azure Inference Chat Client"); | ||||
| var endpointUri = string.IsNullOrEmpty(endpoint) ? null : new Uri(endpoint); | var endpointUri = string.IsNullOrEmpty(endpoint) ? null : new Uri(endpoint); | ||||
| return hostBuilder.Services.AddChatClient(pipeline => | |||||
| { | |||||
| builder?.Invoke(pipeline); | |||||
| var token = Environment.GetEnvironmentVariable("GH_TOKEN") ?? throw new InvalidOperationException("No model access token was found in the environment variable GH_TOKEN"); | |||||
| return pipeline.Use(new ChatCompletionsClient( | |||||
| endpointUri, new AzureKeyCredential(token)).AsChatClient(modelOrDeploymentName)); | |||||
| }); | |||||
| var token = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY") ?? throw new InvalidOperationException("No model access token was found in the environment variable AZURE_OPENAI_API_KEY"); | |||||
| var chatClient = new ChatCompletionsClient(endpointUri, new AzureKeyCredential(token)).AsChatClient(modelOrDeploymentName); | |||||
| hostBuilder.Services.AddChatClient(chatClient); | |||||
| return hostBuilder.Services; | |||||
| } | } | ||||
| } | } | ||||
| @@ -243,7 +243,7 @@ public sealed class GrpcGateway : BackgroundService, IGateway | |||||
| default: | default: | ||||
| await RespondBadRequestAsync(connection, $"Unknown message type for message '{message}'."); | await RespondBadRequestAsync(connection, $"Unknown message type for message '{message}'."); | ||||
| break; | break; | ||||
| }; | |||||
| } | |||||
| } | } | ||||
| /// <summary> | /// <summary> | ||||
| @@ -2,7 +2,7 @@ | |||||
| <PropertyGroup> | <PropertyGroup> | ||||
| <OutputType>Exe</OutputType> | <OutputType>Exe</OutputType> | ||||
| <TargetFramework>net8.0</TargetFramework> | |||||
| <TargetFramework>net8.0</TargetFramework> | |||||
| <ImplicitUsings>enable</ImplicitUsings> | <ImplicitUsings>enable</ImplicitUsings> | ||||
| <Nullable>enable</Nullable> | <Nullable>enable</Nullable> | ||||
| <PublishAot>true</PublishAot> | <PublishAot>true</PublishAot> | ||||
| @@ -12,6 +12,12 @@ | |||||
| "ImageUri": null, | "ImageUri": null, | ||||
| "ImageBytes": null, | "ImageBytes": null, | ||||
| "ImageBytesMediaType": null, | "ImageBytesMediaType": null, | ||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | "ImageDetailLevel": null, | ||||
| "Refusal": null | "Refusal": null | ||||
| } | } | ||||
| @@ -31,6 +37,12 @@ | |||||
| "ImageUri": null, | "ImageUri": null, | ||||
| "ImageBytes": null, | "ImageBytes": null, | ||||
| "ImageBytesMediaType": null, | "ImageBytesMediaType": null, | ||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | "ImageDetailLevel": null, | ||||
| "Refusal": null | "Refusal": null | ||||
| } | } | ||||
| @@ -57,6 +69,12 @@ | |||||
| "ImageUri": null, | "ImageUri": null, | ||||
| "ImageBytes": null, | "ImageBytes": null, | ||||
| "ImageBytesMediaType": null, | "ImageBytesMediaType": null, | ||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | "ImageDetailLevel": null, | ||||
| "Refusal": null | "Refusal": null | ||||
| } | } | ||||
| @@ -78,6 +96,12 @@ | |||||
| "ImageUri": "https://example.com/image.png", | "ImageUri": "https://example.com/image.png", | ||||
| "ImageBytes": null, | "ImageBytes": null, | ||||
| "ImageBytesMediaType": null, | "ImageBytesMediaType": null, | ||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | "ImageDetailLevel": null, | ||||
| "Refusal": null | "Refusal": null | ||||
| } | } | ||||
| @@ -104,6 +128,12 @@ | |||||
| "ImageUri": null, | "ImageUri": null, | ||||
| "ImageBytes": null, | "ImageBytes": null, | ||||
| "ImageBytesMediaType": null, | "ImageBytesMediaType": null, | ||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | "ImageDetailLevel": null, | ||||
| "Refusal": null | "Refusal": null | ||||
| }, | }, | ||||
| @@ -113,6 +143,12 @@ | |||||
| "ImageUri": "https://example.com/image.png", | "ImageUri": "https://example.com/image.png", | ||||
| "ImageBytes": null, | "ImageBytes": null, | ||||
| "ImageBytesMediaType": null, | "ImageBytesMediaType": null, | ||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | "ImageDetailLevel": null, | ||||
| "Refusal": null | "Refusal": null | ||||
| } | } | ||||
| @@ -0,0 +1,260 @@ | |||||
| [ | |||||
| { | |||||
| "OriginalMessage": "TextMessage(system, You are a helpful AI assistant, )", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Name": null, | |||||
| "Role": "system", | |||||
| "Content": [ | |||||
| { | |||||
| "Kind": 0, | |||||
| "Text": "You are a helpful AI assistant", | |||||
| "ImageUri": null, | |||||
| "ImageBytes": null, | |||||
| "ImageBytesMediaType": null, | |||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | |||||
| "Refusal": null | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "TextMessage(user, Hello, user)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "user", | |||||
| "Content": [ | |||||
| { | |||||
| "Kind": 0, | |||||
| "Text": "Hello", | |||||
| "ImageUri": null, | |||||
| "ImageBytes": null, | |||||
| "ImageBytesMediaType": null, | |||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | |||||
| "Refusal": null | |||||
| } | |||||
| ], | |||||
| "Name": "user", | |||||
| "MultiModaItem": [ | |||||
| { | |||||
| "Type": "Text", | |||||
| "Text": "Hello" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "TextMessage(assistant, How can I help you?, assistant)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "assistant", | |||||
| "Content": [ | |||||
| { | |||||
| "Kind": 0, | |||||
| "Text": "How can I help you?", | |||||
| "ImageUri": null, | |||||
| "ImageBytes": null, | |||||
| "ImageBytesMediaType": null, | |||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | |||||
| "Refusal": null | |||||
| } | |||||
| ], | |||||
| "Name": "assistant", | |||||
| "TooCall": [] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "ImageMessage(user, https://example.com/image.png, user)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "user", | |||||
| "Content": [ | |||||
| { | |||||
| "Kind": 2, | |||||
| "Text": null, | |||||
| "ImageUri": "https://example.com/image.png", | |||||
| "ImageBytes": null, | |||||
| "ImageBytesMediaType": null, | |||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | |||||
| "Refusal": null | |||||
| } | |||||
| ], | |||||
| "Name": "user", | |||||
| "MultiModaItem": [ | |||||
| { | |||||
| "Type": "Image", | |||||
| "ImageUrl": "https://example.com/image.png" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "MultiModalMessage(assistant, user)\n\tTextMessage(user, Hello, user)\n\tImageMessage(user, https://example.com/image.png, user)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "user", | |||||
| "Content": [ | |||||
| { | |||||
| "Kind": 0, | |||||
| "Text": "Hello", | |||||
| "ImageUri": null, | |||||
| "ImageBytes": null, | |||||
| "ImageBytesMediaType": null, | |||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | |||||
| "Refusal": null | |||||
| }, | |||||
| { | |||||
| "Kind": 2, | |||||
| "Text": null, | |||||
| "ImageUri": "https://example.com/image.png", | |||||
| "ImageBytes": null, | |||||
| "ImageBytesMediaType": null, | |||||
| "InputAudioBytes": null, | |||||
| "InputAudioFormat": null, | |||||
| "FileId": null, | |||||
| "FileBytes": null, | |||||
| "FileBytesMediaType": null, | |||||
| "Filename": null, | |||||
| "ImageDetailLevel": null, | |||||
| "Refusal": null | |||||
| } | |||||
| ], | |||||
| "Name": "user", | |||||
| "MultiModaItem": [ | |||||
| { | |||||
| "Type": "Text", | |||||
| "Text": "Hello" | |||||
| }, | |||||
| { | |||||
| "Type": "Image", | |||||
| "ImageUrl": "https://example.com/image.png" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "ToolCallMessage(assistant)\n\tToolCall(test, test, )", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "assistant", | |||||
| "Content": [], | |||||
| "Name": null, | |||||
| "TooCall": [ | |||||
| { | |||||
| "Type": "Function", | |||||
| "Name": "test", | |||||
| "Arguments": "dGVzdA==", | |||||
| "Id": "test" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "ToolCallResultMessage(user)\n\tToolCall(test, test, result)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "tool", | |||||
| "Content": "result", | |||||
| "ToolCallId": "test" | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "ToolCallResultMessage(user)\n\tToolCall(result, test, test)\n\tToolCall(result, test, test)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "tool", | |||||
| "Content": "test", | |||||
| "ToolCallId": "result_0" | |||||
| }, | |||||
| { | |||||
| "Role": "tool", | |||||
| "Content": "test", | |||||
| "ToolCallId": "result_1" | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "ToolCallMessage(assistant)\n\tToolCall(test, test, )\n\tToolCall(test, test, )", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "assistant", | |||||
| "Content": [], | |||||
| "Name": null, | |||||
| "TooCall": [ | |||||
| { | |||||
| "Type": "Function", | |||||
| "Name": "test", | |||||
| "Arguments": "dGVzdA==", | |||||
| "Id": "test_0" | |||||
| }, | |||||
| { | |||||
| "Type": "Function", | |||||
| "Name": "test", | |||||
| "Arguments": "dGVzdA==", | |||||
| "Id": "test_1" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "OriginalMessage": "AggregateMessage(assistant)\n\tToolCallMessage(assistant)\n\tToolCall(test, test, )\n\tToolCallResultMessage(assistant)\n\tToolCall(test, test, result)", | |||||
| "ConvertedMessages": [ | |||||
| { | |||||
| "Role": "assistant", | |||||
| "Content": [], | |||||
| "Name": null, | |||||
| "TooCall": [ | |||||
| { | |||||
| "Type": "Function", | |||||
| "Name": "test", | |||||
| "Arguments": "dGVzdA==", | |||||
| "Id": "test" | |||||
| } | |||||
| ] | |||||
| }, | |||||
| { | |||||
| "Role": "tool", | |||||
| "Content": "result", | |||||
| "ToolCallId": "test" | |||||
| } | |||||
| ] | |||||
| } | |||||
| ] | |||||
| @@ -60,7 +60,7 @@ public class FunctionTests | |||||
| GetWeatherAsyncStatic, | GetWeatherAsyncStatic, | ||||
| ]; | ]; | ||||
| var functionContracts = availableDelegates.Select(function => (FunctionContract)AIFunctionFactory.Create(function).Metadata).ToList(); | |||||
| var functionContracts = availableDelegates.Select(function => (FunctionContract)AIFunctionFactory.Create(function)).ToList(); | |||||
| // Verify the function contracts | // Verify the function contracts | ||||
| functionContracts.Should().HaveCount(4); | functionContracts.Should().HaveCount(4); | ||||
| @@ -72,7 +72,7 @@ public partial class MiddlewareTest | |||||
| public async Task FunctionCallMiddlewareTestAsync() | public async Task FunctionCallMiddlewareTestAsync() | ||||
| { | { | ||||
| var agent = new EchoAgent("echo"); | var agent = new EchoAgent("echo"); | ||||
| var args = new EchoSchema { message = "hello" }; | |||||
| var args = new EchoSchema { message = "hello" }; // make the format check happy on linux | |||||
| var argsJson = JsonSerializer.Serialize(args) ?? throw new InvalidOperationException("Failed to serialize args"); | var argsJson = JsonSerializer.Serialize(args) ?? throw new InvalidOperationException("Failed to serialize args"); | ||||
| var functionCall = new ToolCall("Echo", argsJson); | var functionCall = new ToolCall("Echo", argsJson); | ||||
| var functionCallAgent = agent.RegisterMiddleware(async (messages, options, agent, ct) => | var functionCallAgent = agent.RegisterMiddleware(async (messages, options, agent, ct) => | ||||
| @@ -92,7 +92,7 @@ internal sealed class TestGrpcWorkerConnection : IAsyncDisposable | |||||
| default: | default: | ||||
| // if it wasn't recognized return bad request | // if it wasn't recognized return bad request | ||||
| throw new RpcException(new Status(StatusCode.InvalidArgument, $"Unknown message type for message '{message}'")); | throw new RpcException(new Status(StatusCode.InvalidArgument, $"Unknown message type for message '{message}'")); | ||||
| }; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| catch (OperationCanceledException) | catch (OperationCanceledException) | ||||