Refactor project structure (#14)

* refactor abstractions

* refactor structure

* refactor projects WIP

* refactor WIP

* refactoring WIP

* fixes
This commit is contained in:
Kosta Petan
2024-03-21 20:52:05 +01:00
committed by GitHub
parent 04ddb4b85f
commit ec849245ea
72 changed files with 531 additions and 434 deletions

View File

@@ -5,21 +5,17 @@ VisualStudioVersion = 17.5.001.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{088E1138-FF7B-4179-AD37-4E3819C56D7E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "apps", "apps", "{4D8667EC-09BE-4CB1-A278-E1CCD83B62B0}"
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample-apps", "apps", "{4D8667EC-09BE-4CB1-A278-E1CCD83B62B0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gh-flow", "src\apps\gh-flow\gh-flow.csproj", "{37C45587-DD0C-4BFE-817A-21301567A94A}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gh-flow", "src\sample-apps\gh-flow\gh-flow.csproj", "{37C45587-DD0C-4BFE-817A-21301567A94A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "seed-memory", "src\apps\seed-memory\seed-memory.csproj", "{110B2C34-0F48-41CE-BC8F-AE3D24E79627}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "seed-memory", "src\sample-apps\seed-memory\seed-memory.csproj", "{110B2C34-0F48-41CE-BC8F-AE3D24E79627}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkflowsApp", "src\apps\WorkflowsApp\WorkflowsApp.csproj", "{F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkflowsApp", "src\sample-apps\WorkflowsApp\WorkflowsApp.csproj", "{F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "libs", "libs", "{24EB6E3A-C080-4B27-8EA7-F6C91446B840}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.SemanticKernel", "src\libs\Elsa.SemanticKernel\Elsa.SemanticKernel.csproj", "{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AI.DevTeam", "src\libs\Microsoft.AI.DevTeam\Microsoft.AI.DevTeam.csproj", "{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AI.DevTeam.Skills", "src\libs\Microsoft.AI.DevTeam.Skills\Microsoft.AI.DevTeam.Skills.csproj", "{FF3D28B0-9344-44AF-BEEA-260187BE435E}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AI.Agents", "src\libs\Microsoft.AI.Agents\Microsoft.AI.Agents.csproj", "{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -67,18 +63,6 @@ Global
{F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Release|x64.Build.0 = Release|Any CPU
{F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Release|x86.ActiveCfg = Release|Any CPU
{F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Release|x86.Build.0 = Release|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Debug|x64.ActiveCfg = Debug|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Debug|x64.Build.0 = Debug|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Debug|x86.ActiveCfg = Debug|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Debug|x86.Build.0 = Debug|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Release|Any CPU.Build.0 = Release|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Release|x64.ActiveCfg = Release|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Release|x64.Build.0 = Release|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Release|x86.ActiveCfg = Release|Any CPU
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0}.Release|x86.Build.0 = Release|Any CPU
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}.Debug|x64.ActiveCfg = Debug|Any CPU
@@ -91,18 +75,6 @@ Global
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}.Release|x64.Build.0 = Release|Any CPU
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}.Release|x86.ActiveCfg = Release|Any CPU
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1}.Release|x86.Build.0 = Release|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Debug|x64.ActiveCfg = Debug|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Debug|x64.Build.0 = Debug|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Debug|x86.ActiveCfg = Debug|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Debug|x86.Build.0 = Debug|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Release|Any CPU.Build.0 = Release|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Release|x64.ActiveCfg = Release|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Release|x64.Build.0 = Release|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Release|x86.ActiveCfg = Release|Any CPU
{FF3D28B0-9344-44AF-BEEA-260187BE435E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -113,9 +85,7 @@ Global
{110B2C34-0F48-41CE-BC8F-AE3D24E79627} = {4D8667EC-09BE-4CB1-A278-E1CCD83B62B0}
{F288CF45-81EF-4F57-ABAC-D7ABE894E7A0} = {4D8667EC-09BE-4CB1-A278-E1CCD83B62B0}
{24EB6E3A-C080-4B27-8EA7-F6C91446B840} = {088E1138-FF7B-4179-AD37-4E3819C56D7E}
{1F6EE104-0B3F-49C1-BE3B-B93CAD18BAD0} = {24EB6E3A-C080-4B27-8EA7-F6C91446B840}
{9FA8DCFB-1726-42FB-B6CD-8AAC027810A1} = {24EB6E3A-C080-4B27-8EA7-F6C91446B840}
{FF3D28B0-9344-44AF-BEEA-260187BE435E} = {24EB6E3A-C080-4B27-8EA7-F6C91446B840}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {30612385-E4F4-4FD9-B648-45AF74CB4915}

View File

@@ -1,20 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa.EntityFrameworkCore" Version="3.0.6" />
<PackageReference Include="Elsa.EntityFrameworkCore.Sqlite" Version="3.0.6" />
<PackageReference Include="Elsa.Identity" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Designer" Version="3.0.0-preview.727" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\libs\Elsa.SemanticKernel\Elsa.SemanticKernel.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,31 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<Description>
Activities for calling Semantic Kernel SDK
</Description>
<PackageTags>elsa module semantic kernel activities</PackageTags>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa" Version="3.0.6" />
<PackageReference Include="Elsa.Http" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Api" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Core" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Management" Version="3.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="AspNetCore.Authentication.ApiKey" Version="8.0.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.2" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="1.6.2-alpha" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0" />
<ProjectReference Include="..\Microsoft.AI.DevTeam.Skills\Microsoft.AI.DevTeam.Skills.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,4 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Chttpendpoint/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=activities_005Chttptrigger/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View File

@@ -1,25 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 25.0.1705.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Elsa.SemanticKernel", "Elsa.SemanticKernel.csproj", "{9B5A7ECD-F83F-4AF2-8FD7-413FBFEE9509}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9B5A7ECD-F83F-4AF2-8FD7-413FBFEE9509}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B5A7ECD-F83F-4AF2-8FD7-413FBFEE9509}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B5A7ECD-F83F-4AF2-8FD7-413FBFEE9509}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B5A7ECD-F83F-4AF2-8FD7-413FBFEE9509}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EDCC8E64-CF64-4C18-A00D-43F896A0C8FD}
EndGlobalSection
EndGlobal

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear/>
<add key="NuGet official package source" value="https://api.nuget.org/v3/index.json" />
<add key="Jint prereleases" value="https://www.myget.org/F/jint/api/v3/index.json" />
<add key="Elsa prereleases" value="https://f.feedz.io/elsa-workflows/elsa-3/nuget/index.json" />
</packageSources>
</configuration>

View File

@@ -1,10 +1,11 @@
using Orleans.Runtime;
using Orleans.Streams;
namespace Microsoft.AI.DevTeam;
namespace Microsoft.AI.Agents.Abstractions;
public abstract class Agent : Grain, IGrainWithStringKey
{
protected virtual string Namespace { get;set;}
public abstract Task HandleEvent(Event item, StreamSequenceToken? token);
protected async Task PublishEvent(string ns, string id, Event item)
{
@@ -17,7 +18,7 @@ public abstract class Agent : Grain, IGrainWithStringKey
public async override Task OnActivateAsync(CancellationToken cancellationToken)
{
var streamProvider = this.GetStreamProvider("StreamProvider");
var streamId = StreamId.Create(Consts.MainNamespace, this.GetPrimaryKeyString());
var streamId = StreamId.Create(Namespace, this.GetPrimaryKeyString());
var stream = streamProvider.GetStream<Event>(streamId);
await stream.SubscribeAsync(HandleEvent);

View File

@@ -0,0 +1,69 @@
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Orleans.Runtime;
namespace Microsoft.AI.Agents.Abstractions;
public abstract class AiAgent<T> : Agent
{
public AiAgent(
[PersistentState("state", "messages")] IPersistentState<AgentState<T>> state)
{
_state = state;
}
protected IPersistentState<AgentState<T>> _state;
protected void AddToHistory(string message, ChatUserType userType)
{
if (_state.State.History == null) _state.State.History = new List<ChatHistoryItem>();
_state.State.History.Add(new ChatHistoryItem
{
Message = message,
Order = _state.State.History.Count + 1,
UserType = userType
});
}
protected string AppendChatHistory(string ask)
{
AddToHistory(ask, ChatUserType.User);
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)
{
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();
AddToHistory(result, ChatUserType.Agent);
return result;
}
protected async Task<T> ShareContext()
{
return _state.State.Data;
}
}
[Serializable]
public class ChatHistoryItem
{
public string Message { get; set; }
public ChatUserType UserType { get; set; }
public int Order { get; set; }
}
public class AgentState<T>
{
public List<ChatHistoryItem> History { get; set; }
public T Data { get; set; }
}
public enum ChatUserType
{
System,
User,
Agent
}

View File

@@ -0,0 +1,13 @@
namespace Microsoft.AI.Agents.Abstractions
{
[GenerateSerializer]
public class Event
{
[Id(0)]
public string Message { get; set; }
[Id(1)]
public Dictionary<string, string> Data { get; set; }
[Id(2)]
public string Type { get; set; }
}
}

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<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>
</Project>

View File

@@ -1,24 +0,0 @@
namespace Microsoft.AI.DevTeam.Skills;
public static class Skills
{
public static string ForSkillAndFunction(string skillName, string functionName) =>
(skillName, functionName) switch
{
(nameof(PM), nameof(PM.BootstrapProject)) => PM.BootstrapProject,
(nameof(PM), nameof(PM.Readme)) => PM.Readme,
(nameof(DevLead), nameof(DevLead.Plan)) => DevLead.Plan,
(nameof(Developer), nameof(Developer.Implement)) => Developer.Implement,
(nameof(Developer), nameof(Developer.Improve)) => Developer.Improve,
_ => throw new ArgumentException($"Unable to find {skillName}.{functionName}")
};
}
public interface IFunction
{
string Name { get; }
string Description { get; }
string PluginName { get; }
string DefaultValue { get; }
string[] Parameters { get; }
}

View File

@@ -1,12 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.2" />
</ItemGroup>
</Project>

View File

@@ -1,80 +0,0 @@
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Orleans.Runtime;
using Microsoft.KernelMemory;
namespace Microsoft.AI.DevTeam;
public abstract class AiAgent : Agent
{
public AiAgent(
[PersistentState("state", "messages")] IPersistentState<AgentState> state, IKernelMemory memory)
{
_state = state;
_memory = memory;
}
protected readonly IPersistentState<AgentState> _state;
private readonly IKernelMemory _memory;
protected async Task<KernelArguments> CreateWafContext(IKernelMemory memory, string ask)
{
var waf = await memory.AskAsync(ask, index:"waf");
return new KernelArguments{
["input"] = ask,
["wafContext"] = $"Consider the following architectural guidelines: ${waf}"
};
}
protected void AddToHistory(string message, ChatUserType userType)
{
if (_state.State.History == null) _state.State.History = new List<ChatHistoryItem>();
_state.State.History.Add(new ChatHistoryItem
{
Message = message,
Order = _state.State.History.Count + 1,
UserType = userType
});
}
protected string GetChatHistory()
{
return string.Join("\n",_state.State.History.Select(message=> $"{message.UserType}: {message.Message}"));
}
protected async Task<string> CallFunction(string template, string ask, Kernel kernel)
{
var function = kernel.CreateFunctionFromPrompt(template, new OpenAIPromptExecutionSettings { MaxTokens = 15000, Temperature = 0.8, TopP = 1 });
AddToHistory(ask, ChatUserType.User);
var history = GetChatHistory();
var context = await CreateWafContext(_memory, history);
var result = (await kernel.InvokeAsync(function, context)).ToString();
AddToHistory(result, ChatUserType.Agent);
await _state.WriteStateAsync();
return result;
}
}
[Serializable]
public class ChatHistoryItem
{
public string Message { get; set; }
public ChatUserType UserType { get; set; }
public int Order { get; set; }
}
public class AgentState
{
public List<ChatHistoryItem> History { get; set; }
public string Understanding { get; set; }
}
public enum ChatUserType
{
System,
User,
Agent
}

View File

@@ -1,31 +0,0 @@
[GenerateSerializer]
public class Event
{
[Id(0)]
public EventType Type { get; set; }
[Id(1)]
public string Message { get; set; }
[Id(2)]
public Dictionary<string,string> Data { get; set; }
}
public enum EventType
{
NewAsk,
ReadmeChainClosed,
CodeChainClosed,
CodeGenerationRequested,
DevPlanRequested,
ReadmeGenerated,
DevPlanGenerated,
CodeGenerated,
DevPlanChainClosed,
ReadmeRequested,
ReadmeStored,
SandboxRunFinished,
ReadmeCreated,
CodeCreated,
DevPlanCreated,
SandboxRunCreated
}

View File

@@ -1,30 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AnalysisMode>All</AnalysisMode>
</PropertyGroup>
<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="Octokit" Version="10.0.0" />
<PackageReference Include="Azure.ResourceManager.ContainerInstance" Version="1.2.0" />
<PackageReference Include="Azure.Storage.Files.Shares" Version="12.16.0-beta.1" />
<PackageReference Include="Azure.Data.Tables" Version="12.8.1" />
<PackageReference Include="Azure.Identity" Version="1.11.0-beta.1" />
<PackageReference Include="Microsoft.Orleans.Reminders" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Streaming" Version="8.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.4.1" />
<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.35.240318.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference
Include="..\..\libs\Microsoft.AI.DevTeam.Skills\Microsoft.AI.DevTeam.Skills.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Azure;
using Azure.AI.OpenAI;
using Elsa.Extensions;
@@ -11,12 +6,10 @@ using Elsa.Workflows;
using Elsa.Workflows.Contracts;
using Elsa.Workflows.Models;
using Elsa.Workflows.UIHints;
using Microsoft.AI.DevTeam.Skills;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SKDevTeam;
namespace Elsa.SemanticKernel;
@@ -160,18 +153,18 @@ public class SemanticKernelActivityProvider : IActivityProvider
Type[] skillTypes = assembly.GetTypes().ToArray();
foreach (Type skillType in skillTypes)
{
if (skillType.Namespace.Equals("Microsoft.SKDevTeam"))
if (skillType.Namespace.Equals("Microsoft.AI.DevTeam"))
{
skills.Add(skillType.Name);
var functions = skillType.GetFields();
foreach (var function in functions)
{
string field = function.FieldType.ToString();
if (field.Equals("Microsoft.SKDevTeam.SemanticFunctionConfig"))
if (field.Equals("Microsoft.AI.DevTeam.SemanticFunctionConfig"))
{
var promptTemplate = Skills.ForSkillAndFunction(skillType.Name, function.Name);
var promptTemplate = SemanticFunctionConfig.ForSkillAndFunction(skillType.Name, function.Name);
var skfunc = kernel.CreateFunctionFromPrompt(
promptTemplate, new OpenAIPromptExecutionSettings { MaxTokens = 8000, Temperature = 0.4, TopP = 1 });
promptTemplate.PromptTemplate, new OpenAIPromptExecutionSettings { MaxTokens = 8000, Temperature = 0.4, TopP = 1 });
Console.WriteLine($"SKActivityProvider Added SK function: {skfunc.Metadata.PluginName}.{skfunc.Name}");
}

View File

@@ -1,24 +1,17 @@
using Elsa.Extensions;
using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AI.DevTeam.Skills;
using Elsa.Workflows;
using Elsa.Workflows.Attributes;
using Elsa.Workflows.UIHints;
using Elsa.Workflows.Models;
using Microsoft.SKDevTeam;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel;
using Azure.AI.OpenAI;
using Azure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Http.Resilience;
using Microsoft.SemanticKernel.Connectors.OpenAI;
namespace Elsa.SemanticKernel;
@@ -90,9 +83,9 @@ public class SemanticKernelSkill : CodeActivity<string>
var kernel = KernelBuilder();
// load the skill
var promptTemplate = Skills.ForSkillAndFunction(skillName, functionName);
var promptTemplate = SemanticFunctionConfig.ForSkillAndFunction(skillName, functionName);
var function = kernel.CreateFunctionFromPrompt(promptTemplate, new OpenAIPromptExecutionSettings { MaxTokens = 8000, Temperature = 0.4, TopP = 1 });
var function = kernel.CreateFunctionFromPrompt(promptTemplate.PromptTemplate, new OpenAIPromptExecutionSettings { MaxTokens = 8000, Temperature = 0.4, TopP = 1 });
// set the context (our prompt)
var arguments = new KernelArguments{
@@ -188,9 +181,9 @@ public class SemanticKernelSkill : CodeActivity<string>
string field = function.FieldType.ToString();
if (field.Equals("Microsoft.SKDevTeam.SemanticFunctionConfig"))
{
var prompt = Skills.ForSkillAndFunction(skillType.Name, function.Name);
var prompt = SemanticFunctionConfig.ForSkillAndFunction(skillType.Name, function.Name);
var skfunc = kernel.CreateFunctionFromPrompt(
prompt, new OpenAIPromptExecutionSettings { MaxTokens = 8000, Temperature = 0.4, TopP = 1 });
prompt.PromptTemplate, new OpenAIPromptExecutionSettings { MaxTokens = 8000, Temperature = 0.4, TopP = 1 });
Console.WriteLine($"SK Added function: {skfunc.Metadata.PluginName}.{skfunc.Metadata.Name}");
}

View File

@@ -0,0 +1,47 @@
namespace Microsoft.SKDevTeam;
public static class DevLead {
public static SemanticFunctionConfig Plan = new SemanticFunctionConfig
{
PromptTemplate = """
You are a Dev Lead for an application team, building the application described below.
Please break down the steps and modules required to develop the complete application, describe each step in detail.
Make prescriptive architecture, language, and frameowrk choices, do not provide a range of choices.
For each step or module then break down the steps or subtasks required to complete that step or module.
For each subtask write an LLM prompt that would be used to tell a model to write the coee that will accomplish that subtask. If the subtask involves taking action/running commands tell the model to write the script that will run those commands.
In each LLM prompt restrict the model from outputting other text that is not in the form of code or code comments.
Please output a JSON array data structure, in the precise schema shown below, with a list of steps and a description of each step, and the steps or subtasks that each requires, and the LLM prompts for each subtask.
Example:
{
"steps": [
{
"step": "1",
"description": "This is the first step",
"subtasks": [
{
"subtask": "Subtask 1",
"description": "This is the first subtask",
"prompt": "Write the code to do the first subtask"
},
{
"subtask": "Subtask 2",
"description": "This is the second subtask",
"prompt": "Write the code to do the second subtask"
}
]
}
]
}
Do not output any other text.
Input: {{$input}}
{{$wafContext}}
""",
Name = nameof(Plan),
SkillName = nameof(DevLead),
Description = "From a simple description of an application output a development plan for building the application.",
MaxTokens = 6500,
Temperature = 0.0,
TopP = 0.0,
PPenalty = 0.0,
FPenalty = 0.0
};
}

View File

@@ -0,0 +1,46 @@
namespace Microsoft.SKDevTeam;
public static class Developer {
public static SemanticFunctionConfig Implement = new SemanticFunctionConfig
{
PromptTemplate = """
You are a Developer for an application.
Please output the code required to accomplish the task assigned to you below and wrap it in a bash script that creates the files.
Do not use any IDE commands and do not build and run the code.
Make specific choices about implementation. Do not offer a range of options.
Use comments in the code to describe the intent. Do not include other text other than code and code comments.
Input: {{$input}}
{{$wafContext}}
""",
Name = nameof(Implement),
SkillName = nameof(Developer),
Description = "From a description of a coding task out put the code or scripts necessary to complete the task.",
MaxTokens = 6500,
Temperature = 0.0,
TopP = 0.0,
PPenalty = 0.0,
FPenalty = 0.0
};
public static SemanticFunctionConfig Improve = new SemanticFunctionConfig
{
PromptTemplate = """
You are a Developer for an application. Your job is to imrove the code that you are given in the input below.
Please output a new version of code that fixes any problems with this version.
If there is an error message in the input you should fix that error in the code.
Wrap the code output up in a bash script that creates the necessary files by overwriting any previous files.
Do not use any IDE commands and do not build and run the code.
Make specific choices about implementation. Do not offer a range of options.
Use comments in the code to describe the intent. Do not include other text other than code and code comments.
Input: {{$input}}
{{$wafContext}}
""",
Name = nameof(Improve),
SkillName = nameof(Developer),
Description = "From a description of a coding task out put the code or scripts necessary to complete the task.",
MaxTokens = 6500,
Temperature = 0.0,
TopP = 0.0,
PPenalty = 0.0,
FPenalty = 0.0
};
}

View File

@@ -0,0 +1,42 @@
namespace Microsoft.SKDevTeam;
public static class PM
{
public static SemanticFunctionConfig BootstrapProject = new SemanticFunctionConfig
{
PromptTemplate = """
Please write a bash script with the commands that would be required to generate applications as described in the following input.
You may add comments to the script and the generated output but do not add any other text except the bash script.
You may include commands to build the applications but do not run them.
Do not include any git commands.
Input: {{$input}}
{{$wafContext}}
""",
Name = nameof(BootstrapProject),
SkillName = nameof(PM),
Description = "Bootstrap a new project",
MaxTokens = 6500,
Temperature = 0.0,
TopP = 0.0,
PPenalty = 0.0,
FPenalty = 0.0
};
public static SemanticFunctionConfig Readme = new SemanticFunctionConfig
{
PromptTemplate = """
You are a program manager on a software development team. You are working on an app described below.
Based on the input below, and any dialog or other context, please output a raw README.MD markdown file documenting the main features of the app and the architecture or code organization.
Do not describe how to create the application.
Write the README as if it were documenting the features and architecture of the application. You may include instructions for how to run the application.
Input: {{$input}}
{{$wafContext}}
""",
Name = nameof(Readme),
SkillName = nameof(PM),
Description = "From a simple description output a README.md file for a GitHub repository.",
MaxTokens = 6500,
Temperature = 0.0,
TopP = 0.0,
PPenalty = 0.0,
FPenalty = 0.0
};
}

View File

@@ -0,0 +1,23 @@
namespace Microsoft.SKDevTeam;
public class SemanticFunctionConfig
{
public string PromptTemplate { get; set; }
public string Name { get; set; }
public string SkillName { get; set; }
public string Description { get; set; }
public int MaxTokens { get; set; }
public double Temperature { get; set; }
public double TopP { get; set; }
public double PPenalty { get; set; }
public double FPenalty { get; set; }
public static SemanticFunctionConfig ForSkillAndFunction(string skillName, string functionName) =>
(skillName, functionName) switch
{
(nameof(PM), nameof(PM.Readme)) => PM.Readme,
(nameof(DevLead), nameof(DevLead.Plan)) => DevLead.Plan,
(nameof(Developer), nameof(Developer.Implement)) => Developer.Implement,
(nameof(Developer), nameof(Developer.Improve)) => Developer.Improve,
_ => throw new ArgumentException($"Unable to find {skillName}.{functionName}")
};
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Elsa.EntityFrameworkCore" Version="3.0.6" />
<PackageReference Include="Elsa.EntityFrameworkCore.Sqlite" Version="3.0.6" />
<PackageReference Include="Elsa.Identity" Version="3.0.6" />
<PackageReference Include="Elsa" Version="3.0.6" />
<PackageReference Include="Elsa.Http" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Api" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Core" Version="3.0.6" />
<PackageReference Include="Elsa.Workflows.Management" Version="3.0.6" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="AspNetCore.Authentication.ApiKey" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0" />
<PackageReference Include="Elsa.Workflows.Designer" Version="3.0.0-preview.727" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.2" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,33 @@
using Microsoft.AI.Agents.Abstractions;
using Microsoft.KernelMemory;
using Orleans.Runtime;
using Orleans.Streams;
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>
{
protected override string Namespace => Consts.MainNamespace;
public Architect([PersistentState("state", "messages")] IPersistentState<AgentState<ArchitectState>> state, IKernelMemory memory)
: base(state, memory)
{
}
public override Task HandleEvent(Event item, StreamSequenceToken? token)
{
// throw new NotImplementedException();
return Task.CompletedTask;
}
}
[GenerateSerializer]
public class ArchitectState
{
[Id(0)]
public string FilesTree { get; set; }
[Id(1)]
public string HighLevelArchitecture { get; set; }
}

View File

@@ -0,0 +1,30 @@
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Orleans.Runtime;
using Microsoft.AI.Agents.Abstractions;
using Microsoft.SemanticKernel.Connectors.OpenAI;
namespace Microsoft.AI.DevTeam;
public abstract class AzureAiAgent<T> : AiAgent<T>
{
private readonly IKernelMemory _memory;
public AzureAiAgent([PersistentState("state", "messages")] IPersistentState<AgentState<T>> state, IKernelMemory memory) : base(state)
{
_memory = memory;
}
protected async Task<KernelArguments> AddWafContext(IKernelMemory memory, KernelArguments arguments)
{
var waf = await memory.AskAsync(arguments["input"].ToString(), index: "waf");
if (!waf.NoResult) arguments["wafContext"] = $"Consider the following architectural guidelines: ${waf.Result}";
return arguments;
}
protected override async Task<string> CallFunction(string template, KernelArguments arguments, Kernel kernel, OpenAIPromptExecutionSettings? settings = null)
{
var wafArguments = await AddWafContext(_memory, arguments);
return await base.CallFunction(template, wafArguments, kernel, settings);
}
}

View File

@@ -1,4 +1,5 @@
using Orleans.Runtime;
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Orleans.Streams;
namespace Microsoft.AI.DevTeam;
@@ -6,6 +7,7 @@ namespace Microsoft.AI.DevTeam;
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class AzureGenie : Agent
{
protected override string Namespace => Consts.MainNamespace;
private readonly IManageAzure _azureService;
public AzureGenie( IManageAzure azureService)
@@ -17,14 +19,14 @@ public class AzureGenie : Agent
{
switch (item.Type)
{
case EventType.ReadmeCreated:
case nameof(GithubFlowEventType.ReadmeCreated):
{
var parentNumber = long.Parse(item.Data["parentNumber"]);
var issueNumber = long.Parse(item.Data["issueNumber"]);
await Store(item.Data["org"], item.Data["repo"], parentNumber, issueNumber, "readme", "md", "output", item.Message);
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = EventType.ReadmeStored,
Type = nameof(GithubFlowEventType.ReadmeStored),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
@@ -35,7 +37,7 @@ public class AzureGenie : Agent
}
break;
case EventType.CodeCreated:
case nameof(GithubFlowEventType.CodeCreated):
{
var parentNumber = long.Parse(item.Data["parentNumber"]);
var issueNumber = long.Parse(item.Data["issueNumber"]);
@@ -43,7 +45,7 @@ public class AzureGenie : Agent
await RunInSandbox(item.Data["org"], item.Data["repo"], parentNumber, issueNumber);
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = EventType.SandboxRunCreated,
Type = nameof(GithubFlowEventType.SandboxRunCreated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },

View File

@@ -1,20 +1,20 @@
using Microsoft.AI.DevTeam.Skills;
using Microsoft.Extensions.Logging;
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 : AiAgent, IDevelopApps
public class Dev : AzureAiAgent<DeveloperState>, IDevelopApps
{
protected override string Namespace => Consts.MainNamespace;
private readonly Kernel _kernel;
private readonly ILogger<Dev> _logger;
public Dev([PersistentState("state", "messages")] IPersistentState<AgentState> state, Kernel kernel, IKernelMemory memory, ILogger<Dev> logger)
public Dev([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperState>> state, Kernel kernel, IKernelMemory memory, ILogger<Dev> logger)
: base(state, memory)
{
_kernel = kernel;
@@ -25,31 +25,33 @@ public class Dev : AiAgent, IDevelopApps
{
switch (item.Type)
{
case EventType.CodeGenerationRequested:
case nameof(GithubFlowEventType.CodeGenerationRequested):
var code = await GenerateCode(item.Message);
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event {
Type = EventType.CodeGenerated,
Data = new Dictionary<string, string> {
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = nameof(GithubFlowEventType.CodeGenerated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
{ "issueNumber", item.Data["issueNumber"] },
{ "code", code }
},
Message = code
Message = code
});
break;
case EventType.CodeChainClosed:
case nameof(GithubFlowEventType.CodeChainClosed):
var lastCode = _state.State.History.Last().Message;
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event {
Type = EventType.CodeCreated,
Data = new Dictionary<string, string> {
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = nameof(GithubFlowEventType.CodeCreated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
{ "issueNumber", item.Data["issueNumber"] },
{ "code", lastCode },
{ "parentNumber", item.Data["parentNumber"] }
},
Message = lastCode
Message = lastCode
});
break;
default:
@@ -61,7 +63,9 @@ public class Dev : AiAgent, IDevelopApps
{
try
{
return await CallFunction(Developer.Implement, ask, _kernel);
// 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);
}
catch (Exception ex)
{
@@ -105,6 +109,13 @@ public class Dev : AiAgent, IDevelopApps
// }
}
[GenerateSerializer]
public class DeveloperState
{
[Id(0)]
public string Understanding { get; set; }
}
public interface IDevelopApps
{
public Task<string> GenerateCode(string ask);

View File

@@ -1,6 +1,6 @@
namespace Microsoft.AI.DevTeam.Skills;
public static class Developer {
namespace Microsoft.AI.DevTeam;
public static class DeveloperSkills {
public static string Implement = """
You are a Developer for an application.
Please output the code required to accomplish the task assigned to you below and wrap it in a bash script that creates the files.

View File

@@ -1,5 +1,5 @@
namespace Microsoft.AI.DevTeam.Skills;
public static class DevLead {
namespace Microsoft.AI.DevTeam;
public static class DevLeadSkills {
public static string Plan = """
You are a Dev Lead for an application team, building the application described below.
Please break down the steps and modules required to develop the complete application, describe each step in detail.
@@ -30,7 +30,7 @@ public static class DevLead {
]
}
Do not output any other text.
Do not wrap the JSON in any other text, output the JSON format described above.
Do not wrap the JSON in any other text, output the JSON format described above, making sure it's a valid JSON.
Input: {{$input}}
{{$wafContext}}
""";

View File

@@ -1,36 +1,35 @@
using Microsoft.AI.DevTeam.Skills;
using Microsoft.Extensions.Logging;
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Orleans.Runtime;
using Orleans.Streams;
namespace Microsoft.AI.DevTeam;
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class DeveloperLead : AiAgent, ILeadDevelopers
public class DeveloperLead : AzureAiAgent<DeveloperLeadState>, ILeadDevelopers
{
protected override string Namespace => Consts.MainNamespace;
private readonly Kernel _kernel;
private readonly ILogger<DeveloperLead> _logger;
private readonly IManageGithub _ghService;
public DeveloperLead([PersistentState("state", "messages")] IPersistentState<AgentState> state, Kernel kernel, IKernelMemory memory, ILogger<DeveloperLead> logger, IManageGithub ghService)
public DeveloperLead([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperLeadState>> state, Kernel kernel, IKernelMemory memory, ILogger<DeveloperLead> logger)
: base(state, memory)
{
_kernel = kernel;
_logger = logger;
_ghService = ghService;
}
public async override Task HandleEvent(Event item, StreamSequenceToken? token)
{
switch (item.Type)
{
case EventType.DevPlanRequested:
case nameof(GithubFlowEventType.DevPlanRequested):
var plan = await CreatePlan(item.Message);
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = EventType.DevPlanGenerated,
Type = nameof(GithubFlowEventType.DevPlanGenerated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
@@ -40,11 +39,11 @@ public class DeveloperLead : AiAgent, ILeadDevelopers
Message = plan
});
break;
case EventType.DevPlanChainClosed:
case nameof(GithubFlowEventType.DevPlanChainClosed):
var latestPlan = _state.State.History.Last().Message;
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = EventType.DevPlanCreated,
Type = nameof(GithubFlowEventType.DevPlanCreated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
@@ -63,7 +62,10 @@ public class DeveloperLead : AiAgent, ILeadDevelopers
{
try
{
return await CallFunction(DevLead.Plan, ask, _kernel);
// 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);
}
catch (Exception ex)
{
@@ -105,6 +107,7 @@ public class Subtask
public string prompt { get; set; }
}
public class DeveloperLeadState
{
public string Plan { get; set; }
}

View File

@@ -1,8 +1,6 @@
using System.Text.Json;
using Microsoft.AI.DevTeam.Skills;
using Octokit;
using Orleans.Concurrency;
using Orleans.Runtime;
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Orleans.Streams;
namespace Microsoft.AI.DevTeam;
@@ -10,6 +8,7 @@ namespace Microsoft.AI.DevTeam;
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class Hubber : Agent
{
protected override string Namespace => Consts.MainNamespace;
private readonly IManageGithub _ghService;
public Hubber(IManageGithub ghService)
@@ -21,36 +20,37 @@ public class Hubber : Agent
{
switch (item.Type)
{
case EventType.NewAsk:
case nameof(GithubFlowEventType.NewAsk):
{
var parentNumber = long.Parse(item.Data["issueNumber"]);
var pmIssue = await CreateIssue(item.Data["org"], item.Data["repo"], item.Message, $"{nameof(PM)}.{nameof(PM.Readme)}", parentNumber);
var devLeadIssue = await CreateIssue(item.Data["org"], item.Data["repo"], item.Message, $"{nameof(DevLead)}.{nameof(DevLead.Plan)}", parentNumber);
await PostComment(item.Data["org"], item.Data["repo"], parentNumber, $" - #{pmIssue} - tracks {nameof(PM)}.{nameof(PM.Readme)}");
await PostComment(item.Data["org"], item.Data["repo"], parentNumber, $" - #{devLeadIssue} - tracks {nameof(DevLead)}.{nameof(DevLead.Plan)}");
var pmIssue = await CreateIssue(item.Data["org"], item.Data["repo"], item.Message, "PM.Readme", parentNumber);
var devLeadIssue = await CreateIssue(item.Data["org"], item.Data["repo"], item.Message, "DevLead.Plan", parentNumber);
await PostComment(item.Data["org"], item.Data["repo"], parentNumber, $" - #{pmIssue} - tracks PM.Readme");
await PostComment(item.Data["org"], item.Data["repo"], parentNumber, $" - #{devLeadIssue} - tracks DevLead.Plan");
await CreateBranch(item.Data["org"], item.Data["repo"], $"sk-{parentNumber}");
}
break;
case EventType.ReadmeGenerated:
case EventType.DevPlanGenerated:
case EventType.CodeGenerated:
case nameof(GithubFlowEventType.ReadmeGenerated):
case nameof(GithubFlowEventType.DevPlanGenerated):
case nameof(GithubFlowEventType.CodeGenerated):
var contents = string.IsNullOrEmpty(item.Message)? "Sorry, I got tired, can you try again please? ": item.Message;
await PostComment(item.Data["org"], item.Data["repo"], long.Parse(item.Data["issueNumber"]), item.Message);
break;
case EventType.DevPlanCreated:
case nameof(GithubFlowEventType.DevPlanCreated):
{
var plan = JsonSerializer.Deserialize<DevLeadPlanResponse>(item.Data["plan"]);
var prompts = plan.steps.SelectMany(s => s.subtasks.Select(st => st.prompt));
var parentNumber = long.Parse(item.Data["parentNumber"]);
foreach (var prompt in prompts)
{
var functionName = $"{nameof(Developer)}.{nameof(Developer.Implement)}";
var functionName = "Developer.Implement";
var issue = await CreateIssue(item.Data["org"], item.Data["repo"], prompt, functionName, parentNumber);
var commentBody = $" - #{issue} - tracks {functionName}";
await PostComment(item.Data["org"], item.Data["repo"], parentNumber, commentBody);
}
}
break;
case EventType.ReadmeStored:
case nameof(GithubFlowEventType.ReadmeStored):
{
var parentNumber = long.Parse(item.Data["parentNumber"]);
var issueNumber = long.Parse(item.Data["issueNumber"]);
@@ -59,7 +59,7 @@ public class Hubber : Agent
await CreatePullRequest(item.Data["org"], item.Data["repo"], parentNumber, branch);
}
break;
case EventType.SandboxRunFinished:
case nameof(GithubFlowEventType.SandboxRunFinished):
{
var parentNumber = long.Parse(item.Data["parentNumber"]);
var issueNumber = long.Parse(item.Data["issueNumber"]);
@@ -92,4 +92,4 @@ public class Hubber : Agent
{
await _ghService.CommitToBranch(org, repo, parentNumber, issueNumber, rootDir, branch);
}
}
}

View File

@@ -1,5 +1,5 @@
namespace Microsoft.AI.DevTeam.Skills;
public static class PM
namespace Microsoft.AI.DevTeam;
public static class PMSkills
{
public static string BootstrapProject = """
Please write a bash script with the commands that would be required to generate applications as described in the following input.

View File

@@ -1,5 +1,5 @@
using Microsoft.AI.DevTeam.Skills;
using Microsoft.Extensions.Logging;
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Microsoft.KernelMemory;
using Microsoft.SemanticKernel;
using Orleans.Runtime;
@@ -8,12 +8,13 @@ using Orleans.Streams;
namespace Microsoft.AI.DevTeam;
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class ProductManager : AiAgent, IManageProducts
public class ProductManager : AzureAiAgent<ProductManagerState>, IManageProducts
{
protected override string Namespace => Consts.MainNamespace;
private readonly Kernel _kernel;
private readonly ILogger<ProductManager> _logger;
public ProductManager([PersistentState("state", "messages")] IPersistentState<AgentState> state, Kernel kernel, IKernelMemory memory, ILogger<ProductManager> logger)
public ProductManager([PersistentState("state", "messages")] IPersistentState<AgentState<ProductManagerState>> state, Kernel kernel, IKernelMemory memory, ILogger<ProductManager> logger)
: base(state, memory)
{
_kernel = kernel;
@@ -25,10 +26,10 @@ public class ProductManager : AiAgent, IManageProducts
{
switch (item.Type)
{
case EventType.ReadmeRequested:
case nameof(GithubFlowEventType.ReadmeRequested):
var readme = await CreateReadme(item.Message);
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event {
Type = EventType.ReadmeGenerated,
Type = nameof(GithubFlowEventType.ReadmeGenerated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
@@ -38,10 +39,10 @@ public class ProductManager : AiAgent, IManageProducts
Message = readme
});
break;
case EventType.ReadmeChainClosed:
case nameof(GithubFlowEventType.ReadmeChainClosed):
var lastReadme = _state.State.History.Last().Message;
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event {
Type = EventType.ReadmeCreated,
Type = nameof(GithubFlowEventType.ReadmeCreated),
Data = new Dictionary<string, string> {
{ "org", item.Data["org"] },
{ "repo", item.Data["repo"] },
@@ -61,7 +62,8 @@ public class ProductManager : AiAgent, IManageProducts
{
try
{
return await CallFunction(PM.Readme, ask, _kernel);
var context = new KernelArguments { ["input"] = AppendChatHistory(ask)};
return await CallFunction(PMSkills.Readme, context, _kernel);
}
catch (Exception ex)
{
@@ -74,4 +76,11 @@ public class ProductManager : AiAgent, IManageProducts
public interface IManageProducts
{
public Task<string> CreateReadme(string ask);
}
[GenerateSerializer]
public class ProductManagerState
{
[Id(0)]
public string Capabilities { get; set; }
}

View File

@@ -1,4 +1,6 @@
using Orleans.Runtime;
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam.Events;
using Orleans.Runtime;
using Orleans.Streams;
using Orleans.Timers;
@@ -6,6 +8,7 @@ namespace Microsoft.AI.DevTeam;
[ImplicitStreamSubscription(Consts.MainNamespace)]
public class Sandbox : Agent, IRemindable
{
protected override string Namespace => Consts.MainNamespace;
private const string ReminderName = "SandboxRunReminder";
private readonly IManageAzure _azService;
private readonly IReminderRegistry _reminderRegistry;
@@ -24,7 +27,7 @@ public class Sandbox : Agent, IRemindable
{
switch(item.Type)
{
case EventType.SandboxRunCreated:
case nameof(GithubFlowEventType.SandboxRunCreated):
var org = item.Data["org"];
var repo = item.Data["repo"];
var parentIssueNumber = long.Parse(item.Data["parentNumber"]);
@@ -55,7 +58,7 @@ public class Sandbox : Agent, IRemindable
await _azService.DeleteSandbox(sandboxId);
await PublishEvent(Consts.MainNamespace, this.GetPrimaryKeyString(), new Event
{
Type = EventType.SandboxRunFinished,
Type = nameof(GithubFlowEventType.SandboxRunFinished),
Data = new Dictionary<string, string> {
{ "org", _state.State.Org },
{ "repo", _state.State.Repo },
@@ -101,4 +104,4 @@ public class SandboxMetadata
public long ParentIssueNumber { get; set; }
public long IssueNumber { get; set; }
public bool IsCompleted { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
using Microsoft.AI.Agents.Abstractions;
namespace Microsoft.AI.DevTeam.Events
{
public enum GithubFlowEventType
{
NewAsk,
ReadmeChainClosed,
CodeChainClosed,
CodeGenerationRequested,
DevPlanRequested,
ReadmeGenerated,
DevPlanGenerated,
CodeGenerated,
DevPlanChainClosed,
ReadmeRequested,
ReadmeStored,
SandboxRunFinished,
ReadmeCreated,
CodeCreated,
DevPlanCreated,
SandboxRunCreated
}
}

View File

@@ -1,3 +1,4 @@
namespace Microsoft.AI.DevTeam;
public class AzureOptions
{
public string SubscriptionId { get; set; }

View File

@@ -1,3 +1,4 @@
namespace Microsoft.AI.DevTeam;
public class GithubOptions
{
public string AppKey { get; set; }

View File

@@ -1,4 +1,4 @@
namespace Microsoft.AI.DevTeam;
public class OpenAIOptions
{
public string ServiceType { get; set; }

View File

@@ -1,5 +1,4 @@
namespace Microsoft.AI.DevTeam;
public class QdrantOptions
{
public string Endpoint { get; set; }

View File

@@ -1,3 +1,4 @@
namespace Microsoft.AI.DevTeam;
public class ServiceOptions
{
public string IngesterUrl { get; set; }

View File

@@ -1,13 +1,11 @@
using System.Text;
using Azure;
using Azure.Core;
using Azure.Identity;
using Azure.ResourceManager;
using Azure.ResourceManager.ContainerInstance;
using Azure.ResourceManager.ContainerInstance.Models;
using Azure.ResourceManager.Resources;
using Azure.Storage.Files.Shares;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

View File

@@ -1,6 +1,5 @@
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Microsoft.AI.DevTeam;

View File

@@ -1,7 +1,6 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Octokit;

View File

@@ -1,6 +1,5 @@
using System.Text;
using Azure.Storage.Files.Shares;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Octokit;
using Octokit.Helpers;
@@ -215,12 +214,3 @@ public interface IManageGithub
Task<IEnumerable<FileResponse>> GetFiles(string org, string repo, string branch, Func<RepositoryContent, bool> filter);
Task<string> GetMainLanguage(string org, string repo);
}
[GenerateSerializer]
public class NewIssueResponse
{
[Id(0)]
public int IssueNumber { get; set; }
[Id(1)]
public int CommentId { get; set; }
}

View File

@@ -1,5 +1,6 @@
using Microsoft.AI.Agents.Abstractions;
using Microsoft.AI.DevTeam;
using Microsoft.AI.DevTeam.Skills;
using Microsoft.AI.DevTeam.Events;
using Octokit.Webhooks;
using Octokit.Webhooks.Events;
using Octokit.Webhooks.Events.IssueComment;
@@ -7,6 +8,7 @@ using Octokit.Webhooks.Events.Issues;
using Octokit.Webhooks.Models;
using Orleans.Runtime;
namespace Microsoft.AI.DevTeam;
public sealed class GithubWebHookProcessor : WebhookEventProcessor
{
private readonly ILogger<GithubWebHookProcessor> _logger;
@@ -100,10 +102,10 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
var stream = streamProvider.GetStream<Event>(streamId);
var eventType = (skillName, functionName) switch
{
(nameof(PM), nameof(PM.Readme)) => EventType.ReadmeChainClosed,
(nameof(DevLead), nameof(DevLead.Plan)) => EventType.DevPlanChainClosed,
(nameof(Developer), nameof(Developer.Implement)) => EventType.CodeChainClosed,
_ => EventType.NewAsk
("PM","Readme") => nameof(GithubFlowEventType.ReadmeChainClosed),
("DevLead","Plan") => nameof(GithubFlowEventType.DevPlanChainClosed),
("Developer","Implement") => nameof(GithubFlowEventType.CodeChainClosed),
_ => nameof(GithubFlowEventType.NewAsk)
};
var data = new Dictionary<string, string>
{
@@ -131,11 +133,11 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
var eventType = (skillName, functionName) switch
{
("Do", "It") => EventType.NewAsk,
(nameof(PM), nameof(PM.Readme)) => EventType.ReadmeRequested,
(nameof(DevLead), nameof(DevLead.Plan)) => EventType.DevPlanRequested,
(nameof(Developer), nameof(Developer.Implement)) => EventType.CodeGenerationRequested,
_ => EventType.NewAsk
("Do", "It") => nameof(GithubFlowEventType.NewAsk),
("PM","Readme") => nameof(GithubFlowEventType.ReadmeRequested),
("DevLead","Plan") => nameof(GithubFlowEventType.DevPlanRequested),
("Developer","Implement") => nameof(GithubFlowEventType.CodeGenerationRequested),
_ => nameof(GithubFlowEventType.NewAsk)
};
var data = new Dictionary<string, string>
{

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<ItemGroup>
<ProjectReference Include="..\..\libs\Microsoft.AI.DevTeam\Microsoft.AI.DevTeam.csproj" />
<ProjectReference Include="..\..\libs\Microsoft.AI.Agents\Microsoft.AI.Agents.csproj" />
</ItemGroup>
<PropertyGroup>
@@ -16,19 +16,36 @@
<ItemGroup>
<PackageReference Include="Octokit.Webhooks.AspNetCore" Version="2.0.3" />
<PackageReference Include="Octokit" Version="10.0.0" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.6.2" />
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" Version="1.6.2-alpha" />
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" Version="1.6.2-alpha" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Qdrant" Version="0.35.240318.1" />
<PackageReference Include="Microsoft.Orleans.Server" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Sdk" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Runtime" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Persistence.Cosmos" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Clustering.Cosmos" Version="8.0.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
<PackageReference Include="Microsoft.Orleans.Reminders.Cosmos" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.Orleans.Streaming.EventHubs" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Reminders" Version="8.0.0" />
<PackageReference Include="Microsoft.Orleans.Streaming" Version="8.0.0" />
<PackageReference Include="OrleansDashboard" Version="7.2.2" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.21.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.Extensions.Azure" Version="1.7.2" />
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="8.0.0" />
<PackageReference Include="Microsoft.KernelMemory.MemoryDb.Qdrant" Version="0.35.240318.1" />
<PackageReference Include="Azure.ResourceManager.ContainerInstance" Version="1.2.0" />
<PackageReference Include="Azure.Storage.Files.Shares" Version="12.16.0-beta.1" />
<PackageReference Include="Azure.Data.Tables" Version="12.8.1" />
<PackageReference Include="Azure.Identity" Version="1.11.0-beta.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.4.1" />
<PackageReference Include="Microsoft.KernelMemory.Core" Version="0.35.240318.1" />
</ItemGroup>