Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8db5455

Browse files
authoredNov 5, 2024··
Decouple .NET connector from Semantic Kernel (#211)
* Decouple .NET connector from Semantic Kernel: there was just a helper using SK, that can be moved to extension methods for people using SK. No need to depend on SK which could cause version conflicts. * Refactor agent config, replace `IAgentConfig` with `AgentConfigBase`
1 parent e34f2a7 commit 8db5455

File tree

12 files changed

+98
-145
lines changed

12 files changed

+98
-145
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Text;
4+
using Microsoft.SemanticKernel.ChatCompletion;
5+
using Microsoft.SemanticWorkbench.Connector;
6+
7+
namespace AgentExample;
8+
9+
public static class ConnectorExtensions
10+
{
11+
// TODO: the list of participants is incomplete, because agents see only participants being added
12+
public static string GetParticipantName(this Conversation conversation, string id)
13+
{
14+
if (conversation.Participants.TryGetValue(id, out Participant? participant))
15+
{
16+
return participant.Name;
17+
}
18+
19+
return "Unknown";
20+
}
21+
22+
public static ChatHistory ToSemanticKernelChatHistory(
23+
this Conversation conversation,
24+
string assistantId,
25+
string systemPrompt)
26+
{
27+
var result = new ChatHistory(systemPrompt);
28+
29+
foreach (Message msg in conversation.Messages)
30+
{
31+
if (msg.Sender.Id == assistantId)
32+
{
33+
result.AddAssistantMessage(msg.Content!);
34+
}
35+
else
36+
{
37+
result.AddUserMessage(
38+
$"[{conversation.GetParticipantName(msg.Sender.Id)}] {msg.Content}");
39+
}
40+
}
41+
42+
return result;
43+
}
44+
45+
public static string ToHtmlString(
46+
this Conversation conversation,
47+
string assistantId)
48+
{
49+
var result = new StringBuilder();
50+
result.AppendLine("<style>");
51+
result.AppendLine("DIV.conversationHistory { padding: 0 20px 60px 20px; }");
52+
result.AppendLine("DIV.conversationHistory P { margin: 0 0 8px 0; }");
53+
result.AppendLine("</style>");
54+
result.AppendLine("<div class='conversationHistory'>");
55+
56+
foreach (var msg in conversation.Messages)
57+
{
58+
result.AppendLine("<p>");
59+
if (msg.Sender.Id == assistantId)
60+
{
61+
result.AppendLine("<b>Assistant</b><br/>");
62+
}
63+
else
64+
{
65+
result
66+
.Append("<b>")
67+
.Append(conversation.GetParticipantName(msg.Sender.Id))
68+
.AppendLine("</b><br/>");
69+
}
70+
71+
result.AppendLine(msg.Content).AppendLine("</p>");
72+
}
73+
74+
result.Append("</div>");
75+
76+
return result.ToString();
77+
}
78+
}

‎examples/dotnet/dotnet-03-simple-chatbot/MyAgent.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ private async Task<Message> PrepareAnswerAsync(Conversation conversation, Messag
171171

172172
if (inputIsSafe)
173173
{
174-
var chatHistory = conversation.ToChatHistory(this.Id, this.Config.RenderSystemPrompt());
174+
var chatHistory = conversation.ToSemanticKernelChatHistory(this.Id, this.Config.RenderSystemPrompt());
175175
debugInfo.Add("lastChatMsg", chatHistory.Last().Content);
176176

177177
// Show chat history in workbench side panel

‎examples/dotnet/dotnet-03-simple-chatbot/MyAgentConfig.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
namespace AgentExample;
77

8-
public class MyAgentConfig : AgentConfig
8+
public class MyAgentConfig : AgentConfigBase
99
{
1010
// Define safety and behavioral guardrails.
1111
// See https://learn.microsoft.com/azure/ai-services/openai/concepts/system-message for more information and examples.

‎libraries/dotnet/WorkbenchConnector/AgentBase.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
namespace Microsoft.SemanticWorkbench.Connector;
1111

1212
public abstract class AgentBase<TAgentConfig> : IAgentBase
13-
where TAgentConfig : IAgentConfig, new()
13+
where TAgentConfig : AgentConfigBase, new()
1414
{
1515
// Agent instance ID
1616
public string Id { get; protected set; } = string.Empty;

‎libraries/dotnet/WorkbenchConnector/AgentConfig/AgentConfig.cs ‎libraries/dotnet/WorkbenchConnector/AgentConfig/AgentConfigBase.cs

+2-25
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,14 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3-
using System;
43
using System.Collections.Generic;
54
using System.Reflection;
65

76
// ReSharper disable once CheckNamespace
87
namespace Microsoft.SemanticWorkbench.Connector;
98

10-
public class AgentConfig : IAgentConfig
9+
public abstract class AgentConfigBase
1110
{
12-
public AgentConfig()
13-
{
14-
}
15-
16-
public object? ToWorkbenchFormat()
11+
public object ToWorkbenchFormat()
1712
{
1813
Dictionary<string, object> result = new();
1914
Dictionary<string, object> defs = new();
@@ -60,22 +55,4 @@ public AgentConfig()
6055

6156
return result;
6257
}
63-
64-
public void Update(object? config)
65-
{
66-
if (config == null)
67-
{
68-
throw new ArgumentException("Empty configuration");
69-
}
70-
71-
if (config is not AgentConfig cfg)
72-
{
73-
throw new ArgumentException("Incompatible configuration type");
74-
}
75-
76-
foreach (var property in this.GetType().GetProperties())
77-
{
78-
property.SetValue(this, property.GetValue(cfg));
79-
}
80-
}
8158
}

‎libraries/dotnet/WorkbenchConnector/AgentConfig/IAgentConfig.cs

-10
This file was deleted.

‎libraries/dotnet/WorkbenchConnector/Models/ChatHistoryExt.cs

-22
This file was deleted.

‎libraries/dotnet/WorkbenchConnector/Models/Conversation.cs

-64
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
using System.Collections.Generic;
44
using System.Linq;
5-
using System.Text;
65
using System.Text.Json.Serialization;
7-
using Microsoft.SemanticKernel.ChatCompletion;
86

97
// ReSharper disable once CheckNamespace
108
namespace Microsoft.SemanticWorkbench.Connector;
@@ -60,66 +58,4 @@ public void RemoveMessage(Message? msg)
6058

6159
this.Messages = this.Messages.Where(x => x.Id != msg.Id).ToList();
6260
}
63-
64-
public ChatHistory ToChatHistory(string assistantId, string systemPrompt)
65-
{
66-
var result = new ChatHistory(systemPrompt);
67-
68-
foreach (Message msg in this.Messages)
69-
{
70-
if (msg.Sender.Id == assistantId)
71-
{
72-
result.AddAssistantMessage(msg.Content!);
73-
}
74-
else
75-
{
76-
result.AddUserMessage($"[{this.GetParticipantName(msg.Sender.Id)}] {msg.Content}");
77-
}
78-
}
79-
80-
return result;
81-
}
82-
83-
public string ToHtmlString(string assistantId)
84-
{
85-
var result = new StringBuilder();
86-
result.AppendLine("<style>");
87-
result.AppendLine("DIV.conversationHistory { padding: 0 20px 60px 20px; }");
88-
result.AppendLine("DIV.conversationHistory P { margin: 0 0 8px 0; }");
89-
result.AppendLine("</style>");
90-
result.AppendLine("<div class='conversationHistory'>");
91-
92-
foreach (var msg in this.Messages)
93-
{
94-
result.AppendLine("<p>");
95-
if (msg.Sender.Id == assistantId)
96-
{
97-
result.AppendLine("<b>Assistant</b><br/>");
98-
}
99-
else
100-
{
101-
result
102-
.Append("<b>")
103-
.Append(this.GetParticipantName(msg.Sender.Id))
104-
.AppendLine("</b><br/>");
105-
}
106-
107-
result.AppendLine(msg.Content).AppendLine("</p>");
108-
}
109-
110-
result.Append("</div>");
111-
112-
return result.ToString();
113-
}
114-
115-
// TODO: the list of participants is incomplete, because agents see only participants being added
116-
private string GetParticipantName(string id)
117-
{
118-
if (this.Participants.TryGetValue(id, out Participant? participant))
119-
{
120-
return participant.Name;
121-
}
122-
123-
return "Unknown";
124-
}
12561
}

‎libraries/dotnet/WorkbenchConnector/Models/ServiceInfo.cs

+2-4
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,8 @@
77
namespace Microsoft.SemanticWorkbench.Connector;
88

99
public class ServiceInfo<TAgentConfig>(TAgentConfig cfg)
10-
where TAgentConfig : IAgentConfig, new()
10+
where TAgentConfig : AgentConfigBase, new()
1111
{
12-
private readonly TAgentConfig _cfg = cfg;
13-
1412
[JsonPropertyName("assistant_service_id")]
1513
public string ServiceId { get; set; } = string.Empty;
1614

@@ -24,5 +22,5 @@ public class ServiceInfo<TAgentConfig>(TAgentConfig cfg)
2422
public Dictionary<string, object> Metadata { get; set; } = new();
2523

2624
[JsonPropertyName("default_config")]
27-
public object DefaultConfiguration => this._cfg.ToWorkbenchFormat() ?? new();
25+
public object DefaultConfiguration => cfg.ToWorkbenchFormat() ?? new();
2826
}

‎libraries/dotnet/WorkbenchConnector/Webservice.cs

+12-12
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ private sealed class SemanticWorkbenchWebservice
2727

2828
public static WorkbenchConnector<TAgentConfig> UseAgentWebservice<TAgentConfig>(
2929
this IEndpointRouteBuilder builder, string endpoint, bool enableCatchAll = false)
30-
where TAgentConfig : IAgentConfig, new()
30+
where TAgentConfig : AgentConfigBase, new()
3131
{
3232
WorkbenchConnector<TAgentConfig>? workbenchConnector = builder.ServiceProvider.GetService<WorkbenchConnector<TAgentConfig>>();
3333
if (workbenchConnector == null)
@@ -60,7 +60,7 @@ public static WorkbenchConnector<TAgentConfig> UseAgentWebservice<TAgentConfig>(
6060
// Return service details and default agent configuration
6161
public static IEndpointRouteBuilder UseFetchServiceInfo<TAgentConfig>(
6262
this IEndpointRouteBuilder builder, string prefix)
63-
where TAgentConfig : IAgentConfig, new()
63+
where TAgentConfig : AgentConfigBase, new()
6464
{
6565
builder.MapGet(prefix + "/", (
6666
[FromServicesAttribute] WorkbenchConnector<TAgentConfig> workbenchConnector,
@@ -76,7 +76,7 @@ public static IEndpointRouteBuilder UseFetchServiceInfo<TAgentConfig>(
7676
// Create new agent instance
7777
public static IEndpointRouteBuilder UseCreateAgentEndpoint<TAgentConfig>(
7878
this IEndpointRouteBuilder builder, string prefix)
79-
where TAgentConfig : IAgentConfig, new()
79+
where TAgentConfig : AgentConfigBase, new()
8080
{
8181
builder.MapPut(prefix + "/{agentId}",
8282
async (
@@ -110,7 +110,7 @@ await workbenchConnector.CreateAgentAsync(agentId, name, null, cancellationToken
110110
// Delete agent instance
111111
public static IEndpointRouteBuilder UseDeleteAgentEndpoint<TAgentConfig>(
112112
this IEndpointRouteBuilder builder, string prefix)
113-
where TAgentConfig : IAgentConfig, new()
113+
where TAgentConfig : AgentConfigBase, new()
114114
{
115115
builder.MapDelete(prefix + "/{agentId}",
116116
async (
@@ -130,7 +130,7 @@ public static IEndpointRouteBuilder UseDeleteAgentEndpoint<TAgentConfig>(
130130
// Fetch agent configuration
131131
public static IEndpointRouteBuilder UseFetchAgentConfigEndpoint<TAgentConfig>(
132132
this IEndpointRouteBuilder builder, string prefix)
133-
where TAgentConfig : IAgentConfig, new()
133+
where TAgentConfig : AgentConfigBase, new()
134134
{
135135
builder.MapGet(prefix + "/{agentId}/config",
136136
(
@@ -155,7 +155,7 @@ public static IEndpointRouteBuilder UseFetchAgentConfigEndpoint<TAgentConfig>(
155155
// Save agent configuration
156156
public static IEndpointRouteBuilder UseSaveAgentConfigEndpoint<TAgentConfig>(
157157
this IEndpointRouteBuilder builder, string prefix)
158-
where TAgentConfig : IAgentConfig, new()
158+
where TAgentConfig : AgentConfigBase, new()
159159
{
160160
builder.MapPut(prefix + "/{agentId}/config",
161161
async (
@@ -171,7 +171,7 @@ public static IEndpointRouteBuilder UseSaveAgentConfigEndpoint<TAgentConfig>(
171171
if (agent == null) { return Results.NotFound("Agent Not Found"); }
172172

173173
var config = agent.ParseConfig(data["config"]);
174-
IAgentConfig newConfig =
174+
AgentConfigBase newConfig =
175175
await agent.UpdateAgentConfigAsync(config, cancellationToken).ConfigureAwait(false);
176176

177177
var tmp = workbenchConnector.GetAgent(agentId);
@@ -186,7 +186,7 @@ public static IEndpointRouteBuilder UseSaveAgentConfigEndpoint<TAgentConfig>(
186186
// Create new conversation
187187
private static IEndpointRouteBuilder UseCreateConversationEndpoint<TAgentConfig>(
188188
this IEndpointRouteBuilder builder, string prefix)
189-
where TAgentConfig : IAgentConfig, new()
189+
where TAgentConfig : AgentConfigBase, new()
190190
{
191191
builder.MapPut(prefix + "/{agentId}/conversations/{conversationId}",
192192
async (
@@ -214,7 +214,7 @@ private static IEndpointRouteBuilder UseCreateConversationEndpoint<TAgentConfig>
214214
// Fetch conversation states
215215
public static IEndpointRouteBuilder UseFetchConversationStatesEndpoint<TAgentConfig>(
216216
this IEndpointRouteBuilder builder, string prefix)
217-
where TAgentConfig : IAgentConfig, new()
217+
where TAgentConfig : AgentConfigBase, new()
218218
{
219219
builder.MapGet(prefix + "/{agentId}/conversations/{conversationId}/states",
220220
async (
@@ -285,7 +285,7 @@ end of content
285285
// Fetch conversation states
286286
public static IEndpointRouteBuilder UseFetchConversationInsightEndpoint<TAgentConfig>(
287287
this IEndpointRouteBuilder builder, string prefix)
288-
where TAgentConfig : IAgentConfig, new()
288+
where TAgentConfig : AgentConfigBase, new()
289289
{
290290
builder.MapGet(prefix + "/{agentId}/conversations/{conversationId}/states/{insightId}",
291291
async (
@@ -348,7 +348,7 @@ public static IEndpointRouteBuilder UseFetchConversationInsightEndpoint<TAgentCo
348348
// New conversation event
349349
private static IEndpointRouteBuilder UseCreateConversationEventEndpoint<TAgentConfig>(
350350
this IEndpointRouteBuilder builder, string prefix)
351-
where TAgentConfig : IAgentConfig, new()
351+
where TAgentConfig : AgentConfigBase, new()
352352
{
353353
builder.MapPost(prefix + "/{agentId}/conversations/{conversationId}/events",
354354
async (
@@ -539,7 +539,7 @@ private static IEndpointRouteBuilder UseCreateConversationEventEndpoint<TAgentCo
539539
// Delete conversation
540540
public static IEndpointRouteBuilder UseDeleteConversationEndpoint<TAgentConfig>(
541541
this IEndpointRouteBuilder builder, string prefix)
542-
where TAgentConfig : IAgentConfig, new()
542+
where TAgentConfig : AgentConfigBase, new()
543543
{
544544
builder.MapDelete(prefix + "/{agentId}/conversations/{conversationId}",
545545
async (

‎libraries/dotnet/WorkbenchConnector/WorkbenchConnector.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
namespace Microsoft.SemanticWorkbench.Connector;
1414

1515
public abstract class WorkbenchConnector<TAgentConfig> : IDisposable
16-
where TAgentConfig : IAgentConfig, new()
16+
where TAgentConfig : AgentConfigBase, new()
1717
{
1818
protected IAgentServiceStorage Storage { get; private set; }
1919
protected WorkbenchConfig WorkbenchConfig { get; private set; }
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Please sign in to comment.