From f237727e1ab86b13e85ddd3a1740d637b1ec153a Mon Sep 17 00:00:00 2001 From: Devis Lucato Date: Mon, 4 Nov 2024 23:10:16 -0800 Subject: [PATCH] Upgrade .NET connector in the examples (#212) --- examples/dotnet/dotnet-01-echo-bot/MyAgent.cs | 23 +------- .../dotnet-01-echo-bot/MyAgentConfig.cs | 2 +- .../MyWorkbenchConnector.cs | 18 ++++--- examples/dotnet/dotnet-01-echo-bot/Program.cs | 4 +- .../dotnet-01-echo-bot.csproj | 4 +- .../ConnectorExtensions.cs | 53 +++++++++++++++++++ .../dotnet-02-message-types-demo/MyAgent.cs | 23 +------- .../MyAgentConfig.cs | 2 +- .../MyWorkbenchConnector.cs | 18 ++++--- .../dotnet-02-message-types-demo/Program.cs | 4 +- .../dotnet-02-message-types-demo.csproj | 4 +- .../ConnectorExtensions.cs | 1 - .../dotnet-03-simple-chatbot.csproj | 5 +- 13 files changed, 93 insertions(+), 68 deletions(-) create mode 100644 examples/dotnet/dotnet-02-message-types-demo/ConnectorExtensions.cs diff --git a/examples/dotnet/dotnet-01-echo-bot/MyAgent.cs b/examples/dotnet/dotnet-01-echo-bot/MyAgent.cs index 691178d1..77190da7 100644 --- a/examples/dotnet/dotnet-01-echo-bot/MyAgent.cs +++ b/examples/dotnet/dotnet-01-echo-bot/MyAgent.cs @@ -6,15 +6,8 @@ namespace AgentExample; -public class MyAgent : AgentBase +public class MyAgent : AgentBase { - // Agent settings - public MyAgentConfig Config - { - get { return (MyAgentConfig)this.RawConfig; } - private set { this.RawConfig = value; } - } - /// /// Create a new agent instance /// @@ -28,7 +21,7 @@ public MyAgent( string agentId, string agentName, MyAgentConfig? agentConfig, - WorkbenchConnector workbenchConnector, + WorkbenchConnector workbenchConnector, IAgentServiceStorage storage, ILoggerFactory? loggerFactory = null) : base( @@ -43,18 +36,6 @@ public MyAgent( this.Config = JsonSerializer.Deserialize(JsonSerializer.Serialize(agentConfig)) ?? new MyAgentConfig(); } - /// - public override IAgentConfig GetDefaultConfig() - { - return new MyAgentConfig(); - } - - /// - public override IAgentConfig? ParseConfig(object data) - { - return JsonSerializer.Deserialize(JsonSerializer.Serialize(data)); - } - /// public override async Task ReceiveCommandAsync( string conversationId, diff --git a/examples/dotnet/dotnet-01-echo-bot/MyAgentConfig.cs b/examples/dotnet/dotnet-01-echo-bot/MyAgentConfig.cs index f7cca588..03308983 100644 --- a/examples/dotnet/dotnet-01-echo-bot/MyAgentConfig.cs +++ b/examples/dotnet/dotnet-01-echo-bot/MyAgentConfig.cs @@ -5,7 +5,7 @@ namespace AgentExample; -public class MyAgentConfig : AgentConfig +public class MyAgentConfig : AgentConfigBase { [JsonPropertyName(nameof(this.ReplyToAgents))] [JsonPropertyOrder(10)] diff --git a/examples/dotnet/dotnet-01-echo-bot/MyWorkbenchConnector.cs b/examples/dotnet/dotnet-01-echo-bot/MyWorkbenchConnector.cs index cd4f6d6f..74de7098 100644 --- a/examples/dotnet/dotnet-01-echo-bot/MyWorkbenchConnector.cs +++ b/examples/dotnet/dotnet-01-echo-bot/MyWorkbenchConnector.cs @@ -6,9 +6,8 @@ namespace AgentExample; -public sealed class MyWorkbenchConnector : WorkbenchConnector +public sealed class MyWorkbenchConnector : WorkbenchConnector { - private readonly MyAgentConfig _defaultAgentConfig = new(); private readonly IServiceProvider _sp; public MyWorkbenchConnector( @@ -16,9 +15,12 @@ public MyWorkbenchConnector( IConfiguration appConfig, IAgentServiceStorage storage, ILoggerFactory? loggerFactory = null) - : base(appConfig, storage, loggerFactory?.CreateLogger() ?? new NullLogger()) + : base( + workbenchConfig: appConfig.GetSection("Workbench").Get(), + defaultAgentConfig: appConfig.GetSection("Agent").Get(), + storage, + loggerFactory?.CreateLogger() ?? new NullLogger()) { - appConfig.GetSection("Agent").Bind(this._defaultAgentConfig); this._sp = sp; } @@ -33,7 +35,7 @@ public override async Task CreateAgentAsync( this.Log.LogDebug("Creating agent '{0}'", agentId); - MyAgentConfig config = this._defaultAgentConfig; + MyAgentConfig config = this.DefaultAgentConfig; if (configData != null) { var newCfg = JsonSerializer.Deserialize(JsonSerializer.Serialize(configData)); @@ -41,7 +43,11 @@ public override async Task CreateAgentAsync( } // Instantiate using .NET Service Provider so that dependencies are automatically injected - var agent = ActivatorUtilities.CreateInstance(this._sp, agentId, name ?? agentId, config); + var agent = ActivatorUtilities.CreateInstance( + this._sp, + agentId, + name ?? agentId, + config); await agent.StartAsync(cancellationToken).ConfigureAwait(false); this.Agents.TryAdd(agentId, agent); diff --git a/examples/dotnet/dotnet-01-echo-bot/Program.cs b/examples/dotnet/dotnet-01-echo-bot/Program.cs index dddd0c4a..5610efce 100644 --- a/examples/dotnet/dotnet-01-echo-bot/Program.cs +++ b/examples/dotnet/dotnet-01-echo-bot/Program.cs @@ -24,7 +24,7 @@ internal static async Task Main(string[] args) appBuilder.Services.AddSingleton(); // Agent service to support multiple agent instances - appBuilder.Services.AddSingleton(); + appBuilder.Services.AddSingleton, MyWorkbenchConnector>(); // Misc appBuilder.Services.AddLogging() @@ -36,7 +36,7 @@ internal static async Task Main(string[] args) // Connect to workbench backend, keep alive, and accept incoming requests var connectorEndpoint = app.Configuration.GetSection("Workbench").Get()!.ConnectorEndpoint; - using var agentService = app.UseAgentWebservice(connectorEndpoint, true); + using var agentService = app.UseAgentWebservice(connectorEndpoint, true); await agentService.ConnectAsync().ConfigureAwait(false); // Start app and webservice diff --git a/examples/dotnet/dotnet-01-echo-bot/dotnet-01-echo-bot.csproj b/examples/dotnet/dotnet-01-echo-bot/dotnet-01-echo-bot.csproj index 0551e2d6..d26fe821 100644 --- a/examples/dotnet/dotnet-01-echo-bot/dotnet-01-echo-bot.csproj +++ b/examples/dotnet/dotnet-01-echo-bot/dotnet-01-echo-bot.csproj @@ -9,7 +9,7 @@ - + @@ -39,7 +39,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/examples/dotnet/dotnet-02-message-types-demo/ConnectorExtensions.cs b/examples/dotnet/dotnet-02-message-types-demo/ConnectorExtensions.cs new file mode 100644 index 00000000..1fee995a --- /dev/null +++ b/examples/dotnet/dotnet-02-message-types-demo/ConnectorExtensions.cs @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.Text; +using Microsoft.SemanticWorkbench.Connector; + +namespace AgentExample; + +public static class ConnectorExtensions +{ + public static string GetParticipantName(this Conversation conversation, string id) + { + if (conversation.Participants.TryGetValue(id, out Participant? participant)) + { + return participant.Name; + } + + return "Unknown"; + } + + public static string ToHtmlString( + this Conversation conversation, + string assistantId) + { + var result = new StringBuilder(); + result.AppendLine(""); + result.AppendLine("
"); + + foreach (var msg in conversation.Messages) + { + result.AppendLine("

"); + if (msg.Sender.Id == assistantId) + { + result.AppendLine("Assistant
"); + } + else + { + result + .Append("") + .Append(conversation.GetParticipantName(msg.Sender.Id)) + .AppendLine("
"); + } + + result.AppendLine(msg.Content).AppendLine("

"); + } + + result.Append("
"); + + return result.ToString(); + } +} diff --git a/examples/dotnet/dotnet-02-message-types-demo/MyAgent.cs b/examples/dotnet/dotnet-02-message-types-demo/MyAgent.cs index a5364846..cf865fab 100644 --- a/examples/dotnet/dotnet-02-message-types-demo/MyAgent.cs +++ b/examples/dotnet/dotnet-02-message-types-demo/MyAgent.cs @@ -8,15 +8,8 @@ namespace AgentExample; -public class MyAgent : AgentBase +public class MyAgent : AgentBase { - // Agent settings - public MyAgentConfig Config - { - get { return (MyAgentConfig)this.RawConfig; } - private set { this.RawConfig = value; } - } - // Azure Content Safety private readonly ContentSafetyClient _contentSafety; @@ -34,7 +27,7 @@ public MyAgent( string agentId, string agentName, MyAgentConfig? agentConfig, - WorkbenchConnector workbenchConnector, + WorkbenchConnector workbenchConnector, IAgentServiceStorage storage, ContentSafetyClient contentSafety, ILoggerFactory? loggerFactory = null) @@ -51,18 +44,6 @@ public MyAgent( this.Config = JsonSerializer.Deserialize(JsonSerializer.Serialize(agentConfig)) ?? new MyAgentConfig(); } - /// - public override IAgentConfig GetDefaultConfig() - { - return new MyAgentConfig(); - } - - /// - public override IAgentConfig? ParseConfig(object data) - { - return JsonSerializer.Deserialize(JsonSerializer.Serialize(data)); - } - /// public override async Task ReceiveCommandAsync( string conversationId, diff --git a/examples/dotnet/dotnet-02-message-types-demo/MyAgentConfig.cs b/examples/dotnet/dotnet-02-message-types-demo/MyAgentConfig.cs index 216b0021..8d62a4fa 100644 --- a/examples/dotnet/dotnet-02-message-types-demo/MyAgentConfig.cs +++ b/examples/dotnet/dotnet-02-message-types-demo/MyAgentConfig.cs @@ -5,7 +5,7 @@ namespace AgentExample; -public class MyAgentConfig : AgentConfig +public class MyAgentConfig : AgentConfigBase { [JsonPropertyName(nameof(this.ReplyToAgents))] [JsonPropertyOrder(10)] diff --git a/examples/dotnet/dotnet-02-message-types-demo/MyWorkbenchConnector.cs b/examples/dotnet/dotnet-02-message-types-demo/MyWorkbenchConnector.cs index cd4f6d6f..74de7098 100644 --- a/examples/dotnet/dotnet-02-message-types-demo/MyWorkbenchConnector.cs +++ b/examples/dotnet/dotnet-02-message-types-demo/MyWorkbenchConnector.cs @@ -6,9 +6,8 @@ namespace AgentExample; -public sealed class MyWorkbenchConnector : WorkbenchConnector +public sealed class MyWorkbenchConnector : WorkbenchConnector { - private readonly MyAgentConfig _defaultAgentConfig = new(); private readonly IServiceProvider _sp; public MyWorkbenchConnector( @@ -16,9 +15,12 @@ public MyWorkbenchConnector( IConfiguration appConfig, IAgentServiceStorage storage, ILoggerFactory? loggerFactory = null) - : base(appConfig, storage, loggerFactory?.CreateLogger() ?? new NullLogger()) + : base( + workbenchConfig: appConfig.GetSection("Workbench").Get(), + defaultAgentConfig: appConfig.GetSection("Agent").Get(), + storage, + loggerFactory?.CreateLogger() ?? new NullLogger()) { - appConfig.GetSection("Agent").Bind(this._defaultAgentConfig); this._sp = sp; } @@ -33,7 +35,7 @@ public override async Task CreateAgentAsync( this.Log.LogDebug("Creating agent '{0}'", agentId); - MyAgentConfig config = this._defaultAgentConfig; + MyAgentConfig config = this.DefaultAgentConfig; if (configData != null) { var newCfg = JsonSerializer.Deserialize(JsonSerializer.Serialize(configData)); @@ -41,7 +43,11 @@ public override async Task CreateAgentAsync( } // Instantiate using .NET Service Provider so that dependencies are automatically injected - var agent = ActivatorUtilities.CreateInstance(this._sp, agentId, name ?? agentId, config); + var agent = ActivatorUtilities.CreateInstance( + this._sp, + agentId, + name ?? agentId, + config); await agent.StartAsync(cancellationToken).ConfigureAwait(false); this.Agents.TryAdd(agentId, agent); diff --git a/examples/dotnet/dotnet-02-message-types-demo/Program.cs b/examples/dotnet/dotnet-02-message-types-demo/Program.cs index bbbb1f5a..a1f0fe69 100644 --- a/examples/dotnet/dotnet-02-message-types-demo/Program.cs +++ b/examples/dotnet/dotnet-02-message-types-demo/Program.cs @@ -27,7 +27,7 @@ internal static async Task Main(string[] args) appBuilder.Services.AddSingleton(); // Agent service to support multiple agent instances - appBuilder.Services.AddSingleton(); + appBuilder.Services.AddSingleton, MyWorkbenchConnector>(); // Azure AI Content Safety, used to monitor I/O appBuilder.Services.AddAzureAIContentSafety(appBuilder.Configuration.GetSection("AzureContentSafety")); @@ -42,7 +42,7 @@ internal static async Task Main(string[] args) // Connect to workbench backend, keep alive, and accept incoming requests var connectorEndpoint = app.Configuration.GetSection("Workbench").Get()!.ConnectorEndpoint; - using var agentService = app.UseAgentWebservice(connectorEndpoint, true); + using var agentService = app.UseAgentWebservice(connectorEndpoint, true); await agentService.ConnectAsync().ConfigureAwait(false); // Start app and webservice diff --git a/examples/dotnet/dotnet-02-message-types-demo/dotnet-02-message-types-demo.csproj b/examples/dotnet/dotnet-02-message-types-demo/dotnet-02-message-types-demo.csproj index a3ccbcef..0610a1df 100644 --- a/examples/dotnet/dotnet-02-message-types-demo/dotnet-02-message-types-demo.csproj +++ b/examples/dotnet/dotnet-02-message-types-demo/dotnet-02-message-types-demo.csproj @@ -13,7 +13,7 @@ - + @@ -43,7 +43,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/examples/dotnet/dotnet-03-simple-chatbot/ConnectorExtensions.cs b/examples/dotnet/dotnet-03-simple-chatbot/ConnectorExtensions.cs index 882df91a..a4f0f30e 100644 --- a/examples/dotnet/dotnet-03-simple-chatbot/ConnectorExtensions.cs +++ b/examples/dotnet/dotnet-03-simple-chatbot/ConnectorExtensions.cs @@ -8,7 +8,6 @@ namespace AgentExample; public static class ConnectorExtensions { - // TODO: the list of participants is incomplete, because agents see only participants being added public static string GetParticipantName(this Conversation conversation, string id) { if (conversation.Participants.TryGetValue(id, out Participant? participant)) diff --git a/examples/dotnet/dotnet-03-simple-chatbot/dotnet-03-simple-chatbot.csproj b/examples/dotnet/dotnet-03-simple-chatbot/dotnet-03-simple-chatbot.csproj index 8e164a0b..1da7a33e 100644 --- a/examples/dotnet/dotnet-03-simple-chatbot/dotnet-03-simple-chatbot.csproj +++ b/examples/dotnet/dotnet-03-simple-chatbot/dotnet-03-simple-chatbot.csproj @@ -10,8 +10,7 @@
- - + @@ -47,7 +46,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive