Skip to content

Commit

Permalink
Knowledge abstraction to AiAgent (autogenhub#25)
Browse files Browse the repository at this point in the history
* make ghClient fetch synchronous

* refactor memory, extract knowledge adding to AiAgent
  • Loading branch information
kostapetan authored Mar 28, 2024
1 parent 3d90292 commit fda381a
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 159 deletions.
23 changes: 23 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Remove the line below if you want to inherit .editorconfig settings from higher directories
root = true

# C# files
[*.cs]

#### Core EditorConfig Options ####

# Indentation and spacing
indent_size = 4
indent_style = space
tab_width = 4

#### .NET Coding Conventions ####

# this. and Me. preferences
dotnet_style_qualification_for_method = true

#### Diagnostic configuration ####

dotnet_diagnostic.SKEXP0001.severity = none
dotnet_diagnostic.SKEXP0020.severity = none
dotnet_diagnostic.SKEXP0010.severity = none
32 changes: 26 additions & 6 deletions src/libs/Microsoft.AI.Agents/Abstractions/AiAgent.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
using System.Text;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Memory;
using Orleans.Runtime;

namespace Microsoft.AI.Agents.Abstractions;

public abstract class AiAgent<T> : Agent
{
public AiAgent(
[PersistentState("state", "messages")] IPersistentState<AgentState<T>> state)
[PersistentState("state", "messages")] IPersistentState<AgentState<T>> state, ISemanticTextMemory memory, Kernel kernel)
{
_state = state;
_memory = memory;
_kernel = kernel;
}
protected IPersistentState<AgentState<T>> _state;
private readonly ISemanticTextMemory _memory;
private readonly Kernel _kernel;

protected void AddToHistory(string message, ChatUserType userType)
{
Expand All @@ -30,19 +36,33 @@ protected string AppendChatHistory(string ask)
return string.Join("\n", _state.State.History.Select(message => $"{message.UserType}: {message.Message}"));
}

protected virtual async Task<string> CallFunction(string template, KernelArguments arguments, Kernel kernel, OpenAIPromptExecutionSettings? settings = null)
protected virtual async Task<string> CallFunction(string template, KernelArguments arguments, OpenAIPromptExecutionSettings? settings = null)
{
var propmptSettings = (settings == null) ? new OpenAIPromptExecutionSettings { MaxTokens = 18000, Temperature = 0.8, TopP = 1 }
: settings;
var function = kernel.CreateFunctionFromPrompt(template, propmptSettings);
var result = (await kernel.InvokeAsync(function, arguments)).ToString();
var function = _kernel.CreateFunctionFromPrompt(template, propmptSettings);
var result = (await _kernel.InvokeAsync(function, arguments)).ToString();
AddToHistory(result, ChatUserType.Agent);
return result;
}

protected async Task<T> ShareContext()
/// <summary>
/// Adds knowledge to the
/// </summary>
/// <param name="instruction">The instruction string that uses the value of !index! as a placeholder to inject the data. Example:"Consider the following architectural guidelines: {waf}" </param>
/// <param name="index">Knowledge index</param>
/// <param name="arguments">The sk arguments, "input" is the argument </param>
/// <returns></returns>
protected async Task<KernelArguments> AddKnowledge(string instruction, string index, KernelArguments arguments)
{
return _state.State.Data;
var documents = _memory.SearchAsync(index, arguments["input"].ToString(), 5);
var kbStringBuilder = new StringBuilder();
await foreach (var doc in documents)
{
kbStringBuilder.AppendLine($"{doc.Metadata.Text}");
}
arguments[index] = instruction.Replace($"!{index}!", $"{kbStringBuilder}");
return arguments;
}
}

Expand Down
1 change: 0 additions & 1 deletion src/libs/Microsoft.AI.Agents/Microsoft.AI.Agents.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

<ItemGroup>
<PackageReference Include="Microsoft.Orleans.Sdk" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Runtime" Version="8.0.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.2" />
<PackageReference Include="Microsoft.Orleans.Streaming" Version="8.0.0" />
</ItemGroup>
Expand Down
10 changes: 5 additions & 5 deletions src/sample-apps/gh-flow/Agents/Architect/Architect.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Microsoft.AI.Agents.Abstractions;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Memory;
using Orleans.Runtime;
using Orleans.Streams;

Expand All @@ -8,17 +9,16 @@ namespace Microsoft.AI.DevTeam;

// The architect has Org+Repo scope and is holding the knowledge of the high level architecture of the project
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class Architect : AzureAiAgent<ArchitectState>
public class Architect : AiAgent<ArchitectState>
{
protected override string Namespace => Consts.MainNamespace;
public Architect([PersistentState("state", "messages")] IPersistentState<AgentState<ArchitectState>> state, IKernelMemory memory)
: base(state, memory)
public Architect([PersistentState("state", "messages")] IPersistentState<AgentState<ArchitectState>> state, ISemanticTextMemory memory, Kernel kernel)
: base(state, memory, kernel)
{
}

public override Task HandleEvent(Event item, StreamSequenceToken? token)
{
// throw new NotImplementedException();
return Task.CompletedTask;
}
}
Expand Down
30 changes: 0 additions & 30 deletions src/sample-apps/gh-flow/Agents/AzureAiAgent.cs

This file was deleted.

49 changes: 8 additions & 41 deletions src/sample-apps/gh-flow/Agents/Developer/Developer.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Memory;
using Orleans.Runtime;
using Orleans.Streams;

namespace Microsoft.AI.DevTeam;

[ImplicitStreamSubscription(Consts.MainNamespace)]
public class Dev : AzureAiAgent<DeveloperState>, IDevelopApps
public class Dev : AiAgent<DeveloperState>, IDevelopApps
{
protected override string Namespace => Consts.MainNamespace;
private readonly Kernel _kernel;

private readonly ILogger<Dev> _logger;

public Dev([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperState>> state, Kernel kernel, IKernelMemory memory, ILogger<Dev> logger)
: base(state, memory)
public Dev([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<Dev> logger)
: base(state, memory, kernel)
{
_kernel = kernel;
_logger = logger;
}

Expand Down Expand Up @@ -65,48 +64,16 @@ public async Task<string> GenerateCode(string ask)
{
// TODO: ask the architect for the high level architecture as well as the files structure of the project
var context = new KernelArguments { ["input"] = AppendChatHistory(ask)};
return await CallFunction(DeveloperSkills.Implement, context, _kernel);
var instruction = "Consider the following architectural guidelines:!waf!";
var enhancedContext = await AddKnowledge(instruction, "waf",context);
return await CallFunction(DeveloperSkills.Implement, enhancedContext);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error generating code");
return default;
}
}

// public async Task<UnderstandingResult> BuildUnderstanding(string content)
// {
// try
// {
// var explainFunction = _kernel.CreateSemanticFunction(Developer.Explain, new OpenAIRequestSettings { MaxTokens = 15000, Temperature = 0.8, TopP = 1 });
// var consolidateFunction = _kernel.CreateSemanticFunction(Developer.ConsolidateUnderstanding, new OpenAIRequestSettings { MaxTokens = 15000, Temperature = 0.8, TopP = 1 });
// var explainContext = new ContextVariables();
// explainContext.Set("input", content);
// var explainResult = await _kernel.RunAsync(explainContext, explainFunction);
// var explainMesage = explainResult.ToString();

// var consolidateContext = new ContextVariables();
// consolidateContext.Set("input", _state.State.Understanding);
// consolidateContext.Set("newUnderstanding", explainMesage);

// var consolidateResult = await _kernel.RunAsync(consolidateContext, consolidateFunction);
// var consolidateMessage = consolidateResult.ToString();

// _state.State.Understanding = consolidateMessage;
// await _state.WriteStateAsync();

// return new UnderstandingResult
// {
// NewUnderstanding = consolidateMessage,
// Explanation = explainMesage
// };
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "Error building understanding");
// return default;
// }
// }
}

[GenerateSerializer]
Expand Down
19 changes: 9 additions & 10 deletions src/sample-apps/gh-flow/Agents/DeveloperLead/DeveloperLead.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,20 @@
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Memory;
using Orleans.Runtime;
using Orleans.Streams;

namespace Microsoft.AI.DevTeam;
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class DeveloperLead : AzureAiAgent<DeveloperLeadState>, ILeadDevelopers
public class DeveloperLead : AiAgent<DeveloperLeadState>, ILeadDevelopers
{
protected override string Namespace => Consts.MainNamespace;
private readonly Kernel _kernel;
private readonly ILogger<DeveloperLead> _logger;

public DeveloperLead([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperLeadState>> state, Kernel kernel, IKernelMemory memory, ILogger<DeveloperLead> logger)
: base(state, memory)
public DeveloperLead([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperLeadState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<DeveloperLead> logger)
: base(state, memory, kernel)
{
_kernel = kernel;
_logger = logger;
}

Expand Down Expand Up @@ -64,8 +61,10 @@ public async Task<string> CreatePlan(string ask)
{
// TODO: Ask the architect for the existing high level architecture
// as well as the file structure
var context = new KernelArguments { ["input"] = AppendChatHistory(ask)};
return await CallFunction(DevLeadSkills.Plan, context, _kernel);
var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
var instruction = "Consider the following architectural guidelines:!waf!";
var enhancedContext = await AddKnowledge(instruction, "waf", context);
return await CallFunction(DevLeadSkills.Plan, enhancedContext);
}
catch (Exception ex)
{
Expand All @@ -77,7 +76,7 @@ public async Task<string> CreatePlan(string ask)

public interface ILeadDevelopers
{
public Task<string> CreatePlan(string ask);
public Task<string> CreatePlan(string ask);
}

[GenerateSerializer]
Expand Down
15 changes: 7 additions & 8 deletions src/sample-apps/gh-flow/Agents/ProductManager/ProductManager.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Memory;
using Orleans.Runtime;
using Orleans.Streams;

namespace Microsoft.AI.DevTeam;

[ImplicitStreamSubscription(Consts.MainNamespace)]
public class ProductManager : AzureAiAgent<ProductManagerState>, IManageProducts
public class ProductManager : AiAgent<ProductManagerState>, IManageProducts
{
protected override string Namespace => Consts.MainNamespace;
private readonly Kernel _kernel;
private readonly ILogger<ProductManager> _logger;

public ProductManager([PersistentState("state", "messages")] IPersistentState<AgentState<ProductManagerState>> state, Kernel kernel, IKernelMemory memory, ILogger<ProductManager> logger)
: base(state, memory)
public ProductManager([PersistentState("state", "messages")] IPersistentState<AgentState<ProductManagerState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<ProductManager> logger)
: base(state, memory, kernel)
{
_kernel = kernel;
//_memory = memory;
_logger = logger;
}

Expand Down Expand Up @@ -63,7 +60,9 @@ public async Task<string> CreateReadme(string ask)
try
{
var context = new KernelArguments { ["input"] = AppendChatHistory(ask)};
return await CallFunction(PMSkills.Readme, context, _kernel);
var instruction = "Consider the following architectural guidelines:!waf!";
var enhancedContext = await AddKnowledge(instruction, "waf",context);
return await CallFunction(PMSkills.Readme, enhancedContext);
}
catch (Exception ex)
{
Expand Down
Loading

0 comments on commit fda381a

Please sign in to comment.