From 12bf4fef3012f965725da93282a28fbd27a724bb Mon Sep 17 00:00:00 2001 From: Kosta Petan Date: Wed, 11 Oct 2023 21:40:35 +0200 Subject: [PATCH] refactor WIP (#4) Co-authored-by: Kosta Petan --- .../Config/KernelConfigExtensions.cs | 27 --- azure.yaml | 2 +- sk-dev-team.sln | 161 ++++++++++--- .../apps/WorkflowsApp}/.env_example | 0 .../apps/WorkflowsApp}/NuGet.Config | 2 +- .../apps/WorkflowsApp}/Pages/Index.cshtml | 0 .../WorkflowsApp}/Pages/_ViewImports.cshtml | 0 .../apps/WorkflowsApp}/Program.cs | 0 .../Properties/launchSettings.json | 0 .../apps/WorkflowsApp}/WorkflowsApp.csproj | 16 +- .../appsettings.Development.json | 0 .../apps/cli}/Models/DevLeadPlanResponse.cs | 0 {cli => src/apps/cli}/Program.cs | 17 +- {cli => src/apps/cli}/SandboxSkill.cs | 0 {cli => src/apps/cli}/cli.csproj | 6 +- .../apps/cli}/config/KernelSettings.cs | 0 .../apps/cli}/util/Initial Repo Prompt.txt | 0 .../apps/cli}/util/InitialRepoPromptOutput.sh | 0 {cli => src/apps/cli}/util/README.md | 0 .../apps/cli}/util/ReactChatAppPrompt.txt | 0 .../apps/cli}/util/ToDoListSamplePrompt.txt | 0 .../Excuses/FunSkill.Excuses.results.json | 0 .../apps/gh-flow-df}/.vscode/extensions.json | 0 .../apps/gh-flow-df}/.vscode/launch.json | 0 .../apps/gh-flow-df}/.vscode/settings.json | 0 .../apps/gh-flow-df}/.vscode/tasks.json | 0 .../gh-flow-df}/Activities/IssueActivities.cs | 0 .../Activities/MetadataActivities.cs | 0 .../Activities/PullRequestActivities.cs | 0 .../apps/gh-flow-df}/Directory.Build.props | 0 .../apps/gh-flow-df}/Directory.Build.targets | 0 .../apps/gh-flow-df}/Models/AddToPRRequest.cs | 0 .../gh-flow-df}/Models/CloseIssueRequest.cs | 0 .../Models/ContainerInstanceMetadata.cs | 0 .../gh-flow-df}/Models/DevLeadPlanResponse.cs | 0 .../gh-flow-df}/Models/GHCommitRequest.cs | 0 .../apps/gh-flow-df}/Models/GHNewBranch.cs | 0 .../apps/gh-flow-df}/Models/IssueMetadata.cs | 0 .../Models/IssueOrchestrationRequest.cs | 0 .../gh-flow-df}/Models/NewIssueRequest.cs | 0 .../gh-flow-df}/Models/NewIssueResponse.cs | 0 .../gh-flow-df}/Models/RunAndSaveRequest.cs | 0 .../gh-flow-df}/Models/RunInSandboxRequest.cs | 0 .../gh-flow-df}/Models/SaveOutputRequest.cs | 0 .../apps/gh-flow-df}/Models/SkillRequest.cs | 0 .../apps/gh-flow-df}/Models/SkillResponse.cs | 0 .../Orchestrators/IssueOrchestration.cs | 0 .../Orchestrators/SubIssueOrchestration.cs | 0 .../apps/gh-flow-df}/Program.cs | 5 +- .../apps/gh-flow-df}/README.md | 0 .../gh-flow-df}/Services/GithubService.cs | 0 .../Services/WebHookEventProcessor.cs | 0 .../apps/gh-flow-df}/config/AzureOptions.cs | 0 .../apps/gh-flow-df}/config/GithubOptions.cs | 0 .../apps/gh-flow-df}/config/OpenAIOptions.cs | 0 .../apps/gh-flow-df}/config/QdrantOptions.cs | 0 .../apps/gh-flow-df/gh-flow-df.csproj | 6 +- .../apps/gh-flow-df}/host.json | 0 .../apps/gh-flow-df}/local.settings.json | 0 .../gh-flow-df}/local.settings.template.json | 0 src/apps/gh-flow/Program.cs | 111 +++++++++ .../gh-flow/Properties/launchSettings.json | 38 +++ .../Services/GithubWebHookProcessor.cs | 223 ++++++++++++++++++ src/apps/gh-flow/gh-flow.csproj | 23 ++ {util => src/apps}/seed-memory/Dockerfile | 0 {util => src/apps}/seed-memory/Program.cs | 5 +- .../seed-memory/azure-well-architected.pdf | Bin .../seed-memory/config/KernelSettings.cs | 0 .../config/appsettings.template.json | 0 .../apps}/seed-memory/seed-memory.csproj | 4 +- .../SemanticKernelSkillActivityProvider.cs | 14 +- .../Activities/SemanticKernel.cs | 14 +- .../Config/KernelSettings.cs | 0 .../Config/PromptDefaults.cs | 0 .../Elsa.SemanticKernel.csproj | 14 +- .../Elsa.SemanticKernel.csproj.DotSettings | 0 .../Elsa.SemanticKernel.sln | 0 .../libs/Elsa.SemanticKernel}/NuGet.Config | 2 +- .../Actors/Architect/Architect.cs | 26 ++ .../Actors/Conductor/Conductor.cs | 88 +++++++ .../Actors/Conductor/IOrchestrateWorkflows.cs | 11 + .../MS.AI.DevTeam/Actors/DevLead/DevLead.cs | 47 ++++ .../Actors/DevLead/DeveloperLead.cs | 86 +++++++ .../Actors/DevLead/ILeadDevelopment.cs | 7 + .../MS.AI.DevTeam/Actors/Developer/Dev.cs | 45 ++++ .../Actors/Developer/Developer.cs | 45 ++++ .../Actors/Developer/IDevelopCode.cs | 7 + .../Actors/Lookup/ILookupMetadata.cs | 7 + .../MS.AI.DevTeam/Actors/Lookup/Lookup.cs | 42 ++++ .../Actors/ProductManager/IManageProduct.cs | 6 + .../MS.AI.DevTeam/Actors/ProductManager/PM.cs | 23 ++ .../Actors/ProductManager/ProductManager.cs | 40 ++++ .../Actors/Sandbox/IManageSandbox.cs | 6 + .../MS.AI.DevTeam/Actors/Sandbox/Sandbox.cs | 77 ++++++ .../MS.AI.DevTeam/Actors/SemanticPersona.cs | 45 ++++ .../MS.AI.DevTeam/Actors/Tester/Tester.cs | 25 ++ .../Config/SemanticFunctionConfig.cs | 38 +++ src/libs/MS.AI.DevTeam/MS.AI.DevTeam.csproj | 22 ++ .../MS.AI.DevTeam/Options/AzureOptions.cs | 11 + .../MS.AI.DevTeam/Options/GithubOptions.cs | 6 + .../MS.AI.DevTeam/Options/OpenAIOptions.cs | 10 + .../MS.AI.DevTeam/Options/QdrantOptions.cs | 7 + .../MS.AI.DevTeam/Services/AzureService.cs | 151 ++++++++++++ .../Services/GithubAuthService.cs | 35 +++ .../MS.AI.DevTeam/Services/GithubService.cs | 197 ++++++++++++++++ {skills => src/libs/skills}/Chat.cs | 0 {skills => src/libs/skills}/CodeExplainer.cs | 0 {skills => src/libs/skills}/DevLead.cs | 0 {skills => src/libs/skills}/Developer.cs | 0 {skills => src/libs/skills}/PM.cs | 0 .../libs/skills}/SemanticFunctionConfig.cs | 0 {skills => src/libs/skills}/skills.csproj | 0 112 files changed, 1674 insertions(+), 126 deletions(-) delete mode 100644 Elsa.SemanticKernel/Config/KernelConfigExtensions.cs rename {WorkflowsApp => src/apps/WorkflowsApp}/.env_example (100%) rename {Elsa.SemanticKernel => src/apps/WorkflowsApp}/NuGet.Config (76%) rename {WorkflowsApp => src/apps/WorkflowsApp}/Pages/Index.cshtml (100%) rename {WorkflowsApp => src/apps/WorkflowsApp}/Pages/_ViewImports.cshtml (100%) rename {WorkflowsApp => src/apps/WorkflowsApp}/Program.cs (100%) rename {WorkflowsApp => src/apps/WorkflowsApp}/Properties/launchSettings.json (100%) rename {WorkflowsApp => src/apps/WorkflowsApp}/WorkflowsApp.csproj (78%) rename {WorkflowsApp => src/apps/WorkflowsApp}/appsettings.Development.json (100%) rename {cli => src/apps/cli}/Models/DevLeadPlanResponse.cs (100%) rename {cli => src/apps/cli}/Program.cs (90%) rename {cli => src/apps/cli}/SandboxSkill.cs (100%) rename {cli => src/apps/cli}/cli.csproj (84%) rename {cli => src/apps/cli}/config/KernelSettings.cs (100%) rename {cli => src/apps/cli}/util/Initial Repo Prompt.txt (100%) rename {cli => src/apps/cli}/util/InitialRepoPromptOutput.sh (100%) rename {cli => src/apps/cli}/util/README.md (100%) rename {cli => src/apps/cli}/util/ReactChatAppPrompt.txt (100%) rename {cli => src/apps/cli}/util/ToDoListSamplePrompt.txt (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/.semantic-kernel/results/skills/FunSkill/Excuses/FunSkill.Excuses.results.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/.vscode/extensions.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/.vscode/launch.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/.vscode/settings.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/.vscode/tasks.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Activities/IssueActivities.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Activities/MetadataActivities.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Activities/PullRequestActivities.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Directory.Build.props (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Directory.Build.targets (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/AddToPRRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/CloseIssueRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/ContainerInstanceMetadata.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/DevLeadPlanResponse.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/GHCommitRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/GHNewBranch.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/IssueMetadata.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/IssueOrchestrationRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/NewIssueRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/NewIssueResponse.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/RunAndSaveRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/RunInSandboxRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/SaveOutputRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/SkillRequest.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Models/SkillResponse.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Orchestrators/IssueOrchestration.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Orchestrators/SubIssueOrchestration.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Program.cs (96%) rename {sk-azfunc-server => src/apps/gh-flow-df}/README.md (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Services/GithubService.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/Services/WebHookEventProcessor.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/config/AzureOptions.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/config/GithubOptions.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/config/OpenAIOptions.cs (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/config/QdrantOptions.cs (100%) rename sk-azfunc-server/sk-csharp-azure-functions.csproj => src/apps/gh-flow-df/gh-flow-df.csproj (95%) rename {sk-azfunc-server => src/apps/gh-flow-df}/host.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/local.settings.json (100%) rename {sk-azfunc-server => src/apps/gh-flow-df}/local.settings.template.json (100%) create mode 100644 src/apps/gh-flow/Program.cs create mode 100644 src/apps/gh-flow/Properties/launchSettings.json create mode 100644 src/apps/gh-flow/Services/GithubWebHookProcessor.cs create mode 100644 src/apps/gh-flow/gh-flow.csproj rename {util => src/apps}/seed-memory/Dockerfile (100%) rename {util => src/apps}/seed-memory/Program.cs (90%) rename {util => src/apps}/seed-memory/azure-well-architected.pdf (100%) rename {util => src/apps}/seed-memory/config/KernelSettings.cs (100%) rename {util => src/apps}/seed-memory/config/appsettings.template.json (100%) rename {util => src/apps}/seed-memory/seed-memory.csproj (90%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Activities/ActivityProviders/SemanticKernelSkillActivityProvider.cs (93%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Activities/SemanticKernel.cs (92%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Config/KernelSettings.cs (100%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Config/PromptDefaults.cs (100%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Elsa.SemanticKernel.csproj (89%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Elsa.SemanticKernel.csproj.DotSettings (100%) rename {Elsa.SemanticKernel => src/libs/Elsa.SemanticKernel}/Elsa.SemanticKernel.sln (100%) rename {WorkflowsApp => src/libs/Elsa.SemanticKernel}/NuGet.Config (76%) create mode 100644 src/libs/MS.AI.DevTeam/Actors/Architect/Architect.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Conductor/Conductor.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Conductor/IOrchestrateWorkflows.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/DevLead/DevLead.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/DevLead/DeveloperLead.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/DevLead/ILeadDevelopment.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Developer/Dev.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Developer/Developer.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Developer/IDevelopCode.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Lookup/ILookupMetadata.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Lookup/Lookup.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/ProductManager/IManageProduct.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/ProductManager/PM.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/ProductManager/ProductManager.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Sandbox/IManageSandbox.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Sandbox/Sandbox.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/SemanticPersona.cs create mode 100644 src/libs/MS.AI.DevTeam/Actors/Tester/Tester.cs create mode 100644 src/libs/MS.AI.DevTeam/Config/SemanticFunctionConfig.cs create mode 100644 src/libs/MS.AI.DevTeam/MS.AI.DevTeam.csproj create mode 100644 src/libs/MS.AI.DevTeam/Options/AzureOptions.cs create mode 100644 src/libs/MS.AI.DevTeam/Options/GithubOptions.cs create mode 100644 src/libs/MS.AI.DevTeam/Options/OpenAIOptions.cs create mode 100644 src/libs/MS.AI.DevTeam/Options/QdrantOptions.cs create mode 100644 src/libs/MS.AI.DevTeam/Services/AzureService.cs create mode 100644 src/libs/MS.AI.DevTeam/Services/GithubAuthService.cs create mode 100644 src/libs/MS.AI.DevTeam/Services/GithubService.cs rename {skills => src/libs/skills}/Chat.cs (100%) rename {skills => src/libs/skills}/CodeExplainer.cs (100%) rename {skills => src/libs/skills}/DevLead.cs (100%) rename {skills => src/libs/skills}/Developer.cs (100%) rename {skills => src/libs/skills}/PM.cs (100%) rename {skills => src/libs/skills}/SemanticFunctionConfig.cs (100%) rename {skills => src/libs/skills}/skills.csproj (100%) diff --git a/Elsa.SemanticKernel/Config/KernelConfigExtensions.cs b/Elsa.SemanticKernel/Config/KernelConfigExtensions.cs deleted file mode 100644 index 92b8392ef..000000000 --- a/Elsa.SemanticKernel/Config/KernelConfigExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Microsoft.SemanticKernel; - -internal static class KernelConfigExtensions -{ - /// - /// Adds a text completion service to the list. It can be either an OpenAI or Azure OpenAI backend service. - /// - /// - /// - /// - internal static void AddCompletionBackend(this KernelConfig kernelConfig, KernelSettings kernelSettings) - { - switch (kernelSettings.ServiceType.ToUpperInvariant()) - { - case KernelSettings.AzureOpenAI: - kernelConfig.AddAzureChatCompletionService(kernelSettings.DeploymentOrModelId, kernelSettings.Endpoint, kernelSettings.ApiKey); - break; - - case KernelSettings.OpenAI: - kernelConfig.AddOpenAITextCompletionService(modelId: kernelSettings.DeploymentOrModelId, apiKey: kernelSettings.ApiKey, orgId: kernelSettings.OrgId, serviceId: kernelSettings.ServiceId); - break; - - default: - throw new System.Exception($"Invalid service type value: {kernelSettings.ServiceType}"); - } - } -} diff --git a/azure.yaml b/azure.yaml index cf9b6d9db..f56fac572 100644 --- a/azure.yaml +++ b/azure.yaml @@ -3,6 +3,6 @@ name: sk-dev-team services: sk-func: - project: ./sk-azfunc-server + project: ./src/apps/gh-flow-df language: dotnet host: function \ No newline at end of file diff --git a/sk-dev-team.sln b/sk-dev-team.sln index 1ca548760..42943545f 100644 --- a/sk-dev-team.sln +++ b/sk-dev-team.sln @@ -3,39 +3,29 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.001.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "sk-csharp-azure-functions", "sk-azfunc-server\sk-csharp-azure-functions.csproj", "{C787026C-9435-4FD4-AEE5-B005EAEF9E3D}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{088E1138-FF7B-4179-AD37-4E3819C56D7E}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "skills", "skills\skills.csproj", "{51F987E4-3E70-4DB9-9493-AFCFA0CE3773}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "apps", "apps", "{4D8667EC-09BE-4CB1-A278-E1CCD83B62B0}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "cli", "cli\cli.csproj", "{C0073CEA-8A1B-43BC-BADE-F6323CDFA853}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cli", "src\apps\cli\cli.csproj", "{1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "util", "util", "{16A0621E-E1B8-4737-9B3D-08EB9CEF87B0}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gh-flow", "src\apps\gh-flow\gh-flow.csproj", "{37C45587-DD0C-4BFE-817A-21301567A94A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "seed-memory", "util\seed-memory\seed-memory.csproj", "{94C4BF5F-50BF-41CF-8B94-11F39CA430FA}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "gh-flow-df", "src\apps\gh-flow-df\gh-flow-df.csproj", "{CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "seed-memory", "src\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}" +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}") = "MS.AI.DevTeam", "src\libs\MS.AI.DevTeam\MS.AI.DevTeam.csproj", "{A064E523-718C-4464-B8AD-BC00BF2E358A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "skills", "src\libs\skills\skills.csproj", "{3EAFB48F-FBF5-4362-8696-976D7E1EA309}" EndProject Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C787026C-9435-4FD4-AEE5-B005EAEF9E3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C787026C-9435-4FD4-AEE5-B005EAEF9E3D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C787026C-9435-4FD4-AEE5-B005EAEF9E3D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C787026C-9435-4FD4-AEE5-B005EAEF9E3D}.Release|Any CPU.Build.0 = Release|Any CPU - {51F987E4-3E70-4DB9-9493-AFCFA0CE3773}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {51F987E4-3E70-4DB9-9493-AFCFA0CE3773}.Debug|Any CPU.Build.0 = Debug|Any CPU - {51F987E4-3E70-4DB9-9493-AFCFA0CE3773}.Release|Any CPU.ActiveCfg = Release|Any CPU - {51F987E4-3E70-4DB9-9493-AFCFA0CE3773}.Release|Any CPU.Build.0 = Release|Any CPU - {C0073CEA-8A1B-43BC-BADE-F6323CDFA853}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {C0073CEA-8A1B-43BC-BADE-F6323CDFA853}.Debug|Any CPU.Build.0 = Debug|Any CPU - {C0073CEA-8A1B-43BC-BADE-F6323CDFA853}.Release|Any CPU.ActiveCfg = Release|Any CPU - {C0073CEA-8A1B-43BC-BADE-F6323CDFA853}.Release|Any CPU.Build.0 = Release|Any CPU - {94C4BF5F-50BF-41CF-8B94-11F39CA430FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {94C4BF5F-50BF-41CF-8B94-11F39CA430FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {94C4BF5F-50BF-41CF-8B94-11F39CA430FA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {94C4BF5F-50BF-41CF-8B94-11F39CA430FA}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection @@ -43,6 +33,121 @@ Global SolutionGuid = {30612385-E4F4-4FD9-B648-45AF74CB4915} EndGlobalSection GlobalSection(NestedProjects) = preSolution - {94C4BF5F-50BF-41CF-8B94-11F39CA430FA} = {16A0621E-E1B8-4737-9B3D-08EB9CEF87B0} + {4D8667EC-09BE-4CB1-A278-E1CCD83B62B0} = {088E1138-FF7B-4179-AD37-4E3819C56D7E} + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA} = {4D8667EC-09BE-4CB1-A278-E1CCD83B62B0} + {37C45587-DD0C-4BFE-817A-21301567A94A} = {4D8667EC-09BE-4CB1-A278-E1CCD83B62B0} + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3} = {4D8667EC-09BE-4CB1-A278-E1CCD83B62B0} + {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} + {A064E523-718C-4464-B8AD-BC00BF2E358A} = {24EB6E3A-C080-4B27-8EA7-F6C91446B840} + {3EAFB48F-FBF5-4362-8696-976D7E1EA309} = {088E1138-FF7B-4179-AD37-4E3819C56D7E} + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Debug|x64.ActiveCfg = Debug|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Debug|x64.Build.0 = Debug|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Debug|x86.ActiveCfg = Debug|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Debug|x86.Build.0 = Debug|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Release|Any CPU.Build.0 = Release|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Release|x64.ActiveCfg = Release|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Release|x64.Build.0 = Release|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Release|x86.ActiveCfg = Release|Any CPU + {1FE4A9AE-6403-48D6-8D06-A97CCCE608FA}.Release|x86.Build.0 = Release|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Debug|x64.ActiveCfg = Debug|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Debug|x64.Build.0 = Debug|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Debug|x86.ActiveCfg = Debug|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Debug|x86.Build.0 = Debug|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Release|Any CPU.Build.0 = Release|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Release|x64.ActiveCfg = Release|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Release|x64.Build.0 = Release|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Release|x86.ActiveCfg = Release|Any CPU + {37C45587-DD0C-4BFE-817A-21301567A94A}.Release|x86.Build.0 = Release|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Debug|x64.ActiveCfg = Debug|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Debug|x64.Build.0 = Debug|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Debug|x86.ActiveCfg = Debug|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Debug|x86.Build.0 = Debug|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Release|Any CPU.Build.0 = Release|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Release|x64.ActiveCfg = Release|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Release|x64.Build.0 = Release|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Release|x86.ActiveCfg = Release|Any CPU + {CF0F7B0D-3CC4-4068-A1A8-64E3151D01E3}.Release|x86.Build.0 = Release|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Debug|Any CPU.Build.0 = Debug|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Debug|x64.ActiveCfg = Debug|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Debug|x64.Build.0 = Debug|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Debug|x86.ActiveCfg = Debug|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Debug|x86.Build.0 = Debug|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Release|Any CPU.ActiveCfg = Release|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Release|Any CPU.Build.0 = Release|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Release|x64.ActiveCfg = Release|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Release|x64.Build.0 = Release|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Release|x86.ActiveCfg = Release|Any CPU + {110B2C34-0F48-41CE-BC8F-AE3D24E79627}.Release|x86.Build.0 = Release|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Debug|x64.ActiveCfg = Debug|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Debug|x64.Build.0 = Debug|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Debug|x86.ActiveCfg = Debug|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Debug|x86.Build.0 = Debug|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Release|Any CPU.Build.0 = Release|Any CPU + {F288CF45-81EF-4F57-ABAC-D7ABE894E7A0}.Release|x64.ActiveCfg = Release|Any CPU + {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 + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Debug|x64.ActiveCfg = Debug|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Debug|x64.Build.0 = Debug|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Debug|x86.ActiveCfg = Debug|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Debug|x86.Build.0 = Debug|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Release|Any CPU.Build.0 = Release|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Release|x64.ActiveCfg = Release|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Release|x64.Build.0 = Release|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Release|x86.ActiveCfg = Release|Any CPU + {A064E523-718C-4464-B8AD-BC00BF2E358A}.Release|x86.Build.0 = Release|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Debug|x64.ActiveCfg = Debug|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Debug|x64.Build.0 = Debug|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Debug|x86.ActiveCfg = Debug|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Debug|x86.Build.0 = Debug|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Release|Any CPU.Build.0 = Release|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Release|x64.ActiveCfg = Release|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Release|x64.Build.0 = Release|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Release|x86.ActiveCfg = Release|Any CPU + {3EAFB48F-FBF5-4362-8696-976D7E1EA309}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/WorkflowsApp/.env_example b/src/apps/WorkflowsApp/.env_example similarity index 100% rename from WorkflowsApp/.env_example rename to src/apps/WorkflowsApp/.env_example diff --git a/Elsa.SemanticKernel/NuGet.Config b/src/apps/WorkflowsApp/NuGet.Config similarity index 76% rename from Elsa.SemanticKernel/NuGet.Config rename to src/apps/WorkflowsApp/NuGet.Config index 5d2144320..a89a1e8b5 100644 --- a/Elsa.SemanticKernel/NuGet.Config +++ b/src/apps/WorkflowsApp/NuGet.Config @@ -3,7 +3,7 @@ - + diff --git a/WorkflowsApp/Pages/Index.cshtml b/src/apps/WorkflowsApp/Pages/Index.cshtml similarity index 100% rename from WorkflowsApp/Pages/Index.cshtml rename to src/apps/WorkflowsApp/Pages/Index.cshtml diff --git a/WorkflowsApp/Pages/_ViewImports.cshtml b/src/apps/WorkflowsApp/Pages/_ViewImports.cshtml similarity index 100% rename from WorkflowsApp/Pages/_ViewImports.cshtml rename to src/apps/WorkflowsApp/Pages/_ViewImports.cshtml diff --git a/WorkflowsApp/Program.cs b/src/apps/WorkflowsApp/Program.cs similarity index 100% rename from WorkflowsApp/Program.cs rename to src/apps/WorkflowsApp/Program.cs diff --git a/WorkflowsApp/Properties/launchSettings.json b/src/apps/WorkflowsApp/Properties/launchSettings.json similarity index 100% rename from WorkflowsApp/Properties/launchSettings.json rename to src/apps/WorkflowsApp/Properties/launchSettings.json diff --git a/WorkflowsApp/WorkflowsApp.csproj b/src/apps/WorkflowsApp/WorkflowsApp.csproj similarity index 78% rename from WorkflowsApp/WorkflowsApp.csproj rename to src/apps/WorkflowsApp/WorkflowsApp.csproj index 240d57ef4..413793f84 100644 --- a/WorkflowsApp/WorkflowsApp.csproj +++ b/src/apps/WorkflowsApp/WorkflowsApp.csproj @@ -7,13 +7,13 @@ - - - - - - - + diff --git a/src/libs/MS.AI.DevTeam/Actors/Architect/Architect.cs b/src/libs/MS.AI.DevTeam/Actors/Architect/Architect.cs new file mode 100644 index 000000000..f12d90fe5 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Architect/Architect.cs @@ -0,0 +1,26 @@ +using Orleans.Runtime; + +namespace MS.AI.DevTeam; + +public class Architect : SemanticPersona, IArchitectSolutions +{ + public Architect( [PersistentState("state", "messages")]IPersistentState state) : base(state) + { + + } + public Task GenerateProjectStructure(string ask) + { + throw new NotImplementedException(); + } + + public Task ReviewPlan(string plan) + { + throw new NotImplementedException(); + } +} + +public interface IArchitectSolutions : IGrainWithIntegerCompoundKey +{ + Task ReviewPlan(string plan); + Task GenerateProjectStructure(string ask); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/Conductor/Conductor.cs b/src/libs/MS.AI.DevTeam/Actors/Conductor/Conductor.cs new file mode 100644 index 000000000..cae93b2ca --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Conductor/Conductor.cs @@ -0,0 +1,88 @@ +using Orleans.Concurrency; +using Orleans.Runtime; + +namespace MS.AI.DevTeam; + +public class Conductor : Grain, IOrchestrateWorkflows +{ + private readonly IManageGithub _ghService; + public Conductor( IManageGithub ghService) + { + _ghService = ghService; + } + public async Task InitialFlow(string input, string org, string repo, long parentNumber) + { + await _ghService.CreateBranch(new CreateBranchRequest + { + Org = org, + Repo = repo, + Branch = $"sk-{parentNumber}" + }); + + var pmIssue = await _ghService.CreateIssue(new CreateIssueRequest + { + Label = $"{nameof(PM)}.{nameof(PM.Readme)}", + Org = org, + Repo = repo, + Input = input, + ParentNumber = parentNumber + }); + var devLeadIssue = await _ghService.CreateIssue(new CreateIssueRequest + { + Label = $"{nameof(DevLead)}.{nameof(DevLead.Plan)}", + Org = org, + Repo = repo, + Input = input, + ParentNumber = parentNumber + }); + var suffix = $"{org}-{repo}"; + var pm = GrainFactory.GetGrain(pmIssue.IssueNumber, suffix); + var devLead = GrainFactory.GetGrain(devLeadIssue.IssueNumber, suffix); + var lookup = GrainFactory.GetGrain(suffix); + + var metadataList = new List{ + new StoreMetadataPairs + { + Key = pmIssue.IssueNumber, + Value = new NewIssueResponse { CommentId = pmIssue.CommentId, IssueNumber = (int)parentNumber} + }, + new StoreMetadataPairs + { + Key = devLeadIssue.IssueNumber, + Value = new NewIssueResponse { CommentId = devLeadIssue.CommentId, IssueNumber = (int)parentNumber} + } + }; + await lookup.StoreMetadata(metadataList); + + // await githubActor.CreatePR(); // TODO: this should happen when all tasks are done? + } + public async Task ImplementationFlow(DevLeadPlanResponse plan, string org, string repo, int parentNumber) + { + var suffix = $"{org}-{repo}"; + var prompts = plan.steps.SelectMany(s => s.subtasks.Select(st => st.prompt)); + var lookup = GrainFactory.GetGrain(suffix); + var metadataList = new List(); + foreach(var prompt in prompts) + { + var issue = await _ghService.CreateIssue(new CreateIssueRequest + { + Label = $"{nameof(Dev)}.{nameof(Dev.Implement)}", + Org = org, + Repo = repo, + Input = prompt, + ParentNumber = parentNumber + }); + metadataList.Add(new StoreMetadataPairs + { + Key = issue.IssueNumber, + Value = new NewIssueResponse { CommentId = issue.CommentId, IssueNumber = (int)parentNumber} + }); + } + await lookup.StoreMetadata(metadataList); + } + + public Task ScheduleCommitSandboxRun(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest) + { + throw new NotImplementedException(); + } +} diff --git a/src/libs/MS.AI.DevTeam/Actors/Conductor/IOrchestrateWorkflows.cs b/src/libs/MS.AI.DevTeam/Actors/Conductor/IOrchestrateWorkflows.cs new file mode 100644 index 000000000..b23349310 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Conductor/IOrchestrateWorkflows.cs @@ -0,0 +1,11 @@ +using Orleans.Concurrency; + +namespace MS.AI.DevTeam; + +public interface IOrchestrateWorkflows : IGrainWithIntegerCompoundKey +{ + [OneWay] + Task InitialFlow(string input, string org, string repo, long parentNumber); + [OneWay] + Task ImplementationFlow(DevLeadPlanResponse plan, string org, string repo, int parentNumber); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/DevLead/DevLead.cs b/src/libs/MS.AI.DevTeam/Actors/DevLead/DevLead.cs new file mode 100644 index 000000000..8563a21b8 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/DevLead/DevLead.cs @@ -0,0 +1,47 @@ +namespace MS.AI.DevTeam; + +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}} + """, + 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 + }; +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/DevLead/DeveloperLead.cs b/src/libs/MS.AI.DevTeam/Actors/DevLead/DeveloperLead.cs new file mode 100644 index 000000000..033187aa8 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/DevLead/DeveloperLead.cs @@ -0,0 +1,86 @@ +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Orchestration; +using Orleans.Runtime; +using System.Text.Json; + +namespace MS.AI.DevTeam; +public class DeveloperLead : SemanticPersona, ILeadDevelopment +{ + private readonly IKernel _kernel; + protected override string MemorySegment => "dev-lead-memory"; + + public DeveloperLead(IKernel kernel, [PersistentState("state", "messages")] IPersistentState state) : base(state) + { + _kernel = kernel; + } + public async Task CreatePlan(string ask) + { + // var architectId = Guid.NewGuid(); + // var plan = "this is my plan"; + // var architect = GrainFactory.GetGrain(architectId); + // var review = architect.ReviewPlan(plan); + // return Task.FromResult(plan); + + var function = _kernel.LoadFunction(nameof(DevLead), nameof(DevLead.Plan)); + var context = new ContextVariables(); + context.Set("input", ask); + if (_state.State.History == null) _state.State.History = new List(); + _state.State.History.Add(new ChatHistoryItem + { + Message = ask, + Order = _state.State.History.Count + 1, + UserType = ChatUserType.User + }); + context.Set("input", ask); + + var result = await _kernel.RunAsync(context, function); + var resultMessage = result.ToString(); + _state.State.History.Add(new ChatHistoryItem + { + Message = resultMessage, + Order = _state.State.History.Count + 1, + UserType = ChatUserType.Agent + }); + await _state.WriteStateAsync(); + + return resultMessage; + } + + public Task GetLatestPlan() + { + var plan = _state.State.History.Last().Message; + var response = JsonSerializer.Deserialize(plan); + return Task.FromResult(response); + } +} + +[GenerateSerializer] +public class DevLeadPlanResponse +{ + [Id(0)] + public List steps { get; set; } +} + +[GenerateSerializer] +public class Step +{ + [Id(0)] + public string description { get; set; } + [Id(1)] + public string step { get; set; } + [Id(2)] + public List subtasks { get; set; } +} + +[GenerateSerializer] +public class Subtask +{ + [Id(0)] + public string subtask { get; set; } + [Id(1)] + public string prompt { get; set; } +} + + + + diff --git a/src/libs/MS.AI.DevTeam/Actors/DevLead/ILeadDevelopment.cs b/src/libs/MS.AI.DevTeam/Actors/DevLead/ILeadDevelopment.cs new file mode 100644 index 000000000..18cf4f324 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/DevLead/ILeadDevelopment.cs @@ -0,0 +1,7 @@ +namespace MS.AI.DevTeam; + +public interface ILeadDevelopment: IGrainWithIntegerCompoundKey, IChatHistory +{ + Task CreatePlan(string ask); + Task GetLatestPlan(); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/Developer/Dev.cs b/src/libs/MS.AI.DevTeam/Actors/Developer/Dev.cs new file mode 100644 index 000000000..607d7842d --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Developer/Dev.cs @@ -0,0 +1,45 @@ +namespace MS.AI.DevTeam; + +public static class Dev { + 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}} + """, + 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}} + """, + 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 + }; +} diff --git a/src/libs/MS.AI.DevTeam/Actors/Developer/Developer.cs b/src/libs/MS.AI.DevTeam/Actors/Developer/Developer.cs new file mode 100644 index 000000000..c062a6d62 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Developer/Developer.cs @@ -0,0 +1,45 @@ +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Orchestration; +using Orleans.Runtime; + +namespace MS.AI.DevTeam; + +public class Developer : SemanticPersona, IDevelopCode +{ + private readonly IKernel _kernel; + protected override string MemorySegment => "dev-memory"; + + public Developer(IKernel kernel, [PersistentState("state", "messages")]IPersistentState state) : base(state) + { + _kernel = kernel; + } + + public async Task GenerateCode(string ask) + { + var function = _kernel.LoadFunction(nameof(Dev), nameof(Dev.Implement)); + var context = new ContextVariables(); + if (_state.State.History == null) _state.State.History = new List(); + _state.State.History.Add(new ChatHistoryItem{ + Message = ask, + Order = _state.State.History.Count+1, + UserType = ChatUserType.User + }); + context.Set("input", ask); + + var result = await _kernel.RunAsync(context, function); + var resultMessage = result.ToString(); + _state.State.History.Add(new ChatHistoryItem{ + Message = resultMessage, + Order = _state.State.History.Count+1, + UserType = ChatUserType.Agent + }); + await _state.WriteStateAsync(); + + return resultMessage; + } + + public Task ReviewPlan(string plan) + { + throw new NotImplementedException(); + } +} diff --git a/src/libs/MS.AI.DevTeam/Actors/Developer/IDevelopCode.cs b/src/libs/MS.AI.DevTeam/Actors/Developer/IDevelopCode.cs new file mode 100644 index 000000000..bafb81ac9 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Developer/IDevelopCode.cs @@ -0,0 +1,7 @@ +namespace MS.AI.DevTeam; + +public interface IDevelopCode : IGrainWithIntegerCompoundKey, IChatHistory +{ + Task GenerateCode(string ask); + Task ReviewPlan(string plan); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/Lookup/ILookupMetadata.cs b/src/libs/MS.AI.DevTeam/Actors/Lookup/ILookupMetadata.cs new file mode 100644 index 000000000..4bd1ba23c --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Lookup/ILookupMetadata.cs @@ -0,0 +1,7 @@ +namespace MS.AI.DevTeam; + +public interface ILookupMetadata : IGrainWithStringKey +{ + Task GetMetadata(int key); + Task StoreMetadata(List pairs); +} diff --git a/src/libs/MS.AI.DevTeam/Actors/Lookup/Lookup.cs b/src/libs/MS.AI.DevTeam/Actors/Lookup/Lookup.cs new file mode 100644 index 000000000..d4c19da43 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Lookup/Lookup.cs @@ -0,0 +1,42 @@ +using Orleans.Runtime; + +namespace MS.AI.DevTeam; + +public class Lookup : Grain, ILookupMetadata +{ + protected readonly IPersistentState _state; + public Lookup([PersistentState("state", "messages")] IPersistentState state) + { + _state = state; + } + + public Task GetMetadata(int key) + { + return Task.FromResult(_state.State.Metadata[key]); + } + + public Task StoreMetadata(List pairs) + { + if(_state.State.Metadata == null) _state.State.Metadata = new Dictionary(); + foreach(var pair in pairs) + { + _state.State.Metadata[pair.Key] = pair.Value; + } + return _state.WriteStateAsync(); + } +} + +[Serializable] +public class ConductorLookup +{ + public Dictionary Metadata { get; set; } +} + +[GenerateSerializer] +public class StoreMetadataPairs +{ + [Id(0)] + public int Key { get; set; } + [Id(1)] + public NewIssueResponse Value { get; set; } +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/ProductManager/IManageProduct.cs b/src/libs/MS.AI.DevTeam/Actors/ProductManager/IManageProduct.cs new file mode 100644 index 000000000..9cc36ac6e --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/ProductManager/IManageProduct.cs @@ -0,0 +1,6 @@ +namespace MS.AI.DevTeam; + +public interface IManageProduct : IGrainWithIntegerCompoundKey, IChatHistory +{ + Task CreateReadme(string ask); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/ProductManager/PM.cs b/src/libs/MS.AI.DevTeam/Actors/ProductManager/PM.cs new file mode 100644 index 000000000..5eac53072 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/ProductManager/PM.cs @@ -0,0 +1,23 @@ +namespace MS.AI.DevTeam; + +public static class PM +{ + 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}} + """, + 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 + }; +} diff --git a/src/libs/MS.AI.DevTeam/Actors/ProductManager/ProductManager.cs b/src/libs/MS.AI.DevTeam/Actors/ProductManager/ProductManager.cs new file mode 100644 index 000000000..e29051bb2 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/ProductManager/ProductManager.cs @@ -0,0 +1,40 @@ +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.Orchestration; +using Orleans.Runtime; + +namespace MS.AI.DevTeam; +public class ProductManager : SemanticPersona, IManageProduct +{ + private readonly IKernel _kernel; + protected override string MemorySegment => "pm-memory"; + + public ProductManager(IKernel kernel,[PersistentState("state", "messages")] IPersistentState state) : base(state) + { + _kernel = kernel; + } + public async Task CreateReadme(string ask) + { + var function = _kernel.LoadFunction(nameof(PM), nameof(PM.Readme)); + var context = new ContextVariables(); + context.Set("input", ask); + if(_state.State.History == null) _state.State.History = new List(); + _state.State.History.Add(new ChatHistoryItem + { + Message = ask, + Order = _state.State.History.Count + 1, + UserType = ChatUserType.User + }); + context.Set("input", ask); + + var result = await _kernel.RunAsync(context, function); + var resultMessage = result.ToString(); + _state.State.History.Add(new ChatHistoryItem + { + Message = resultMessage, + Order = _state.State.History.Count + 1, + UserType = ChatUserType.Agent + }); + await _state.WriteStateAsync(); + return resultMessage; + } +} diff --git a/src/libs/MS.AI.DevTeam/Actors/Sandbox/IManageSandbox.cs b/src/libs/MS.AI.DevTeam/Actors/Sandbox/IManageSandbox.cs new file mode 100644 index 000000000..d874fb952 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Sandbox/IManageSandbox.cs @@ -0,0 +1,6 @@ +namespace MS.AI.DevTeam; + +public interface IManageSandbox : IGrainWithIntegerCompoundKey +{ + Task ScheduleCommitSandboxRun(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/Sandbox/Sandbox.cs b/src/libs/MS.AI.DevTeam/Actors/Sandbox/Sandbox.cs new file mode 100644 index 000000000..6a5f28675 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Sandbox/Sandbox.cs @@ -0,0 +1,77 @@ +namespace MS.AI.DevTeam; +using Orleans.Runtime; +using Orleans.Timers; + +public class Sandbox : Grain, IManageSandbox, IRemindable +{ + private const string ReminderName = "SandboxRunReminder"; + private readonly IManageGithub _ghService; + private readonly IManageAzure _azService; + private readonly IReminderRegistry _reminderRegistry; + private IGrainReminder? _reminder; + + protected readonly IPersistentState _state; + + public Sandbox([PersistentState("state", "messages")] IPersistentState state, IManageGithub ghService, + IReminderRegistry reminderRegistry, IManageAzure azService) + { + _ghService = ghService; + _reminderRegistry = reminderRegistry; + _azService = azService; + _state = state; + } + public async Task ScheduleCommitSandboxRun(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest) + { + await StoreState(commitRequest, markTaskCompleteRequest, sandboxRequest); + _reminder = await _reminderRegistry.RegisterOrUpdateReminder( + callingGrainId: this.GetGrainId(), + reminderName: ReminderName, + dueTime: TimeSpan.Zero, + period: TimeSpan.FromMinutes(1)); + } + + async Task IRemindable.ReceiveReminder(string reminderName, TickStatus status) + { + if (!_state.State.IsCompleted) + { + var sandboxId = $"sk-sandbox-{_state.State.SandboxRequest.Org}-{_state.State.SandboxRequest.Repo}-{_state.State.SandboxRequest.ParentIssueNumber}-{_state.State.SandboxRequest.IssueNumber}"; + if (await _azService.IsSandboxCompleted(sandboxId)) + { + await _azService.DeleteSandbox(sandboxId); + await _ghService.CommitToBranch(_state.State.CommitRequest); + await _ghService.MarkTaskComplete(_state.State.MarkTaskCompleteRequest); + await Cleanup(); + } + } + else + { + await Cleanup(); + } + } + + private async Task StoreState(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest) + { + _state.State.CommitRequest = commitRequest; + _state.State.MarkTaskCompleteRequest = markTaskCompleteRequest; + _state.State.SandboxRequest = sandboxRequest; + _state.State.IsCompleted = false; + await _state.WriteStateAsync(); + } + + private async Task Cleanup() + { + _state.State.IsCompleted = true; + await _reminderRegistry.UnregisterReminder( + this.GetGrainId(), _reminder); + await _state.WriteStateAsync(); + } +} + + +public class SandboxMetadata +{ + public CommitRequest CommitRequest { get; set; } + public MarkTaskCompleteRequest MarkTaskCompleteRequest { get; set; } + public SandboxRequest SandboxRequest { get; set; } + public bool IsCompleted { get; set; } +} diff --git a/src/libs/MS.AI.DevTeam/Actors/SemanticPersona.cs b/src/libs/MS.AI.DevTeam/Actors/SemanticPersona.cs new file mode 100644 index 000000000..0bfb88adf --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/SemanticPersona.cs @@ -0,0 +1,45 @@ +using Orleans.Runtime; + +public abstract class SemanticPersona : Grain, IChatHistory +{ + public SemanticPersona( + [PersistentState("state", "messages")] IPersistentState state) + { + _state = state; + } + protected virtual string MemorySegment { get; set; } + protected List History { get; set; } + protected readonly IPersistentState _state; + + public async Task GetLastMessage() + { + return _state.State.History.Last().Message; + } +} + +public interface IChatHistory +{ + Task GetLastMessage(); +} + + +[Serializable] +public class ChatHistoryItem +{ + public string Message { get; set; } + public ChatUserType UserType { get; set; } + public int Order { get; set; } + +} + +public class ChatHistory +{ + public List History { get; set; } +} + +public enum ChatUserType +{ + System, + User, + Agent +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Actors/Tester/Tester.cs b/src/libs/MS.AI.DevTeam/Actors/Tester/Tester.cs new file mode 100644 index 000000000..0b7466a60 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Actors/Tester/Tester.cs @@ -0,0 +1,25 @@ +using Orleans.Runtime; + +public class Tester : SemanticPersona, ITestCode +{ + public Tester( + [PersistentState("state", "messages")]IPersistentState state) : base(state) + { + + } + public Task ReviewPlan(string plan) + { + throw new NotImplementedException(); + } + + public Task TestCode(string ask) + { + throw new NotImplementedException(); + } +} + +public interface ITestCode : IGrainWithIntegerCompoundKey +{ + Task TestCode(string ask); + Task ReviewPlan(string plan); +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Config/SemanticFunctionConfig.cs b/src/libs/MS.AI.DevTeam/Config/SemanticFunctionConfig.cs new file mode 100644 index 000000000..1c61a8b0f --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Config/SemanticFunctionConfig.cs @@ -0,0 +1,38 @@ +using Microsoft.SemanticKernel; +using Microsoft.SemanticKernel.SkillDefinition; + +namespace MS.AI.DevTeam; + +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(CodeExplainer), nameof(CodeExplainer.Explain)) => CodeExplainer.Explain, + (nameof(Dev), nameof(Dev.Implement)) => Dev.Implement, + // (nameof(Developer), nameof(Developer.Improve)) => Developer.Improve, + _ => throw new ArgumentException($"Unable to find {skillName}.{functionName}") + }; +} + +public static class SemanticKernelExtensions +{ + public static ISKFunction LoadFunction(this IKernel kernel, string skill, string function) + { + var skillConfig = SemanticFunctionConfig.ForSkillAndFunction(skill, function); + return kernel.CreateSemanticFunction(skillConfig.PromptTemplate, skillConfig.Name, skillConfig.SkillName, + skillConfig.Description, skillConfig.MaxTokens, skillConfig.Temperature, + skillConfig.TopP, skillConfig.PPenalty, skillConfig.FPenalty); + } +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/MS.AI.DevTeam.csproj b/src/libs/MS.AI.DevTeam/MS.AI.DevTeam.csproj new file mode 100644 index 000000000..1dfa8f6dd --- /dev/null +++ b/src/libs/MS.AI.DevTeam/MS.AI.DevTeam.csproj @@ -0,0 +1,22 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + + + + diff --git a/src/libs/MS.AI.DevTeam/Options/AzureOptions.cs b/src/libs/MS.AI.DevTeam/Options/AzureOptions.cs new file mode 100644 index 000000000..362b1f883 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Options/AzureOptions.cs @@ -0,0 +1,11 @@ +public class AzureOptions +{ + public string SubscriptionId { get; set; } + public string Location { get; set; } + public string ContainerInstancesResourceGroup { get; set; } + public string FilesShareName { get; set; } + public string FilesAccountName { get; set; } + public string FilesAccountKey { get; set; } + public string CosmosConnectionString { get; set; } + public string SandboxImage { get; set; } +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Options/GithubOptions.cs b/src/libs/MS.AI.DevTeam/Options/GithubOptions.cs new file mode 100644 index 000000000..90ed5cdc0 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Options/GithubOptions.cs @@ -0,0 +1,6 @@ +public class GithubOptions +{ + public string AppKey { get; set; } + public int AppId { get; set; } + public long InstallationId { get; set; } +} diff --git a/src/libs/MS.AI.DevTeam/Options/OpenAIOptions.cs b/src/libs/MS.AI.DevTeam/Options/OpenAIOptions.cs new file mode 100644 index 000000000..9f752153b --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Options/OpenAIOptions.cs @@ -0,0 +1,10 @@ + +public class OpenAIOptions +{ + public string ServiceType { get; set; } + public string ServiceId { get; set; } + public string DeploymentOrModelId { get; set; } + public string EmbeddingDeploymentOrModelId { get; set; } + public string Endpoint { get; set; } + public string ApiKey { get; set; } +} diff --git a/src/libs/MS.AI.DevTeam/Options/QdrantOptions.cs b/src/libs/MS.AI.DevTeam/Options/QdrantOptions.cs new file mode 100644 index 000000000..9d12defc4 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Options/QdrantOptions.cs @@ -0,0 +1,7 @@ + + +public class QdrantOptions +{ + public string Endpoint { get; set; } + public int VectorSize { get; set; } +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Services/AzureService.cs b/src/libs/MS.AI.DevTeam/Services/AzureService.cs new file mode 100644 index 000000000..a23d1e94d --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Services/AzureService.cs @@ -0,0 +1,151 @@ +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.Options; + + +namespace MS.AI.DevTeam; + +public class AzureService : IManageAzure +{ + private readonly AzureOptions _azSettings; + + public AzureService(IOptions azOptions) + { + _azSettings = azOptions.Value; + } + + public async Task DeleteSandbox(string sandboxId) + { + var client = new ArmClient(new DefaultAzureCredential()); + var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup); + var resourceGroupResource = client.GetResourceGroupResource(resourceGroupResourceId); + + var collection = resourceGroupResource.GetContainerGroups(); + var containerGroup = await collection.GetAsync(sandboxId); + await containerGroup.Value.DeleteAsync(WaitUntil.Started); + } + + public async Task IsSandboxCompleted(string sandboxId) + { + var client = new ArmClient(new DefaultAzureCredential()); + var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup); + var resourceGroupResource = client.GetResourceGroupResource(resourceGroupResourceId); + + var collection = resourceGroupResource.GetContainerGroups(); + var containerGroup = await collection.GetAsync(sandboxId); + return containerGroup.Value.Data.ProvisioningState == "Succeeded" + && containerGroup.Value.Data.Containers.First().InstanceView.CurrentState.State == "Terminated"; + } + + public async Task RunInSandbox(SandboxRequest request) + { + var client = new ArmClient(new DefaultAzureCredential()); + var runId = $"sk-sandbox-{request.Org}-{request.Repo}-{request.ParentIssueNumber}-{request.IssueNumber}"; + var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup); + var resourceGroupResource = client.GetResourceGroupResource(resourceGroupResourceId); + var scriptPath = $"/azfiles/output/{request.Org}-{request.Repo}/{request.ParentIssueNumber}/{request.IssueNumber}/run.sh"; + var collection = resourceGroupResource.GetContainerGroups(); + var data = new ContainerGroupData(new AzureLocation(_azSettings.Location), new ContainerInstanceContainer[] + { + new ContainerInstanceContainer(runId,_azSettings.SandboxImage,new ContainerResourceRequirements(new ContainerResourceRequestsContent(1.5,1))) + { + Command = { "/bin/bash", $"{scriptPath}" }, + VolumeMounts = + { + new ContainerVolumeMount("azfiles","/azfiles/") + { + IsReadOnly = false, + } + }, + }}, ContainerInstanceOperatingSystemType.Linux) + { + Volumes = + { + new ContainerVolume("azfiles") + { + AzureFile = new ContainerInstanceAzureFileVolume(_azSettings.FilesShareName,_azSettings.FilesAccountName) + { + StorageAccountKey = _azSettings.FilesAccountKey + }, + }, + }, + RestartPolicy = ContainerGroupRestartPolicy.Never, + Sku = ContainerGroupSku.Standard, + Priority = ContainerGroupPriority.Regular + }; + await collection.CreateOrUpdateAsync(WaitUntil.Completed, runId, data); + } + + public async Task Store(SaveOutputRequest request) + { + var connectionString = $"DefaultEndpointsProtocol=https;AccountName={_azSettings.FilesAccountName};AccountKey={_azSettings.FilesAccountKey};EndpointSuffix=core.windows.net"; + var parentDirName = $"{request.Directory}/{request.Org}-{request.Repo}"; + + var fileName = $"{request.FileName}.{request.Extension}"; + + var share = new ShareClient(connectionString, _azSettings.FilesShareName); + await share.CreateIfNotExistsAsync(); + await share.GetDirectoryClient($"{request.Directory}").CreateIfNotExistsAsync(); ; + + var parentDir = share.GetDirectoryClient(parentDirName); + await parentDir.CreateIfNotExistsAsync(); + + var parentIssueDir = parentDir.GetSubdirectoryClient($"{request.ParentIssueNumber}"); + await parentIssueDir.CreateIfNotExistsAsync(); + + var directory = parentIssueDir.GetSubdirectoryClient($"{request.IssueNumber}"); + await directory.CreateIfNotExistsAsync(); + + var file = directory.GetFileClient(fileName); + // hack to enable script to save files in the same directory + var cwdHack = "#!/bin/bash\n cd $(dirname $0)"; + var output = request.Extension == "sh" ? request.Output.Replace("#!/bin/bash", cwdHack) : request.Output; + using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(output))) + { + await file.CreateAsync(stream.Length); + await file.UploadRangeAsync( + new HttpRange(0, stream.Length), + stream); + } + } +} + +public interface IManageAzure +{ + Task Store(SaveOutputRequest request); + Task RunInSandbox(SandboxRequest request); + Task IsSandboxCompleted(string sandboxId); + Task DeleteSandbox(string sandboxId); +} + +public class SaveOutputRequest +{ + public int ParentIssueNumber { get; set; } + public int IssueNumber { get; set; } + public string Output { get; set; } + public string Extension { get; set; } + public string Directory { get; set; } + public string FileName { get; set; } + public string Org { get; set; } + public string Repo { get; set; } +} + +[GenerateSerializer] +public class SandboxRequest +{ + [Id(0)] + public string Org { get; set; } + [Id(1)] + public string Repo { get; set; } + [Id(2)] + public int IssueNumber { get; set; } + [Id(3)] + public int ParentIssueNumber { get; set; } +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Services/GithubAuthService.cs b/src/libs/MS.AI.DevTeam/Services/GithubAuthService.cs new file mode 100644 index 000000000..8bc01b88f --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Services/GithubAuthService.cs @@ -0,0 +1,35 @@ +using Microsoft.Extensions.Options; +using Octokit; + +public class GithubAuthService +{ + private readonly GithubOptions _githubSettings; + + public GithubAuthService(IOptions ghOptions) + { + _githubSettings = ghOptions.Value; + } + public async Task GetGitHubClient() + { + // Use GitHubJwt library to create the GitHubApp Jwt Token using our private certificate PEM file + var generator = new GitHubJwt.GitHubJwtFactory( + new GitHubJwt.StringPrivateKeySource(_githubSettings.AppKey), + new GitHubJwt.GitHubJwtFactoryOptions + { + AppIntegrationId = _githubSettings.AppId, // The GitHub App Id + ExpirationSeconds = 600 // 10 minutes is the maximum time allowed + } + ); + + var jwtToken = generator.CreateEncodedJwtToken(); + var appClient = new GitHubClient(new ProductHeaderValue("SK-DEV-APP")) + { + Credentials = new Credentials(jwtToken, AuthenticationType.Bearer) + }; + var response = await appClient.GitHubApps.CreateInstallationToken(_githubSettings.InstallationId); + return new GitHubClient(new ProductHeaderValue($"SK-DEV-APP-Installation{_githubSettings.InstallationId}")) + { + Credentials = new Credentials(response.Token) + }; + } +} \ No newline at end of file diff --git a/src/libs/MS.AI.DevTeam/Services/GithubService.cs b/src/libs/MS.AI.DevTeam/Services/GithubService.cs new file mode 100644 index 000000000..5666e12f7 --- /dev/null +++ b/src/libs/MS.AI.DevTeam/Services/GithubService.cs @@ -0,0 +1,197 @@ +using System.Text; +using Azure.Storage.Files.Shares; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Octokit; +using Octokit.Helpers; + + +namespace MS.AI.DevTeam; + +public class GithubService : IManageGithub +{ + private readonly GitHubClient _ghClient; + private readonly AzureOptions _azSettings; + private readonly ILogger logger; + + public GithubService(GitHubClient ghClient, IOptions azOptions, ILogger logger) + { + _ghClient = ghClient; + _azSettings = azOptions.Value; + this.logger = logger; + } + + public async Task CommitToBranch(CommitRequest request) + { + var connectionString = $"DefaultEndpointsProtocol=https;AccountName={_azSettings.FilesAccountName};AccountKey={_azSettings.FilesAccountKey};EndpointSuffix=core.windows.net"; + + var dirName = $"{request.Dir}/{request.Org}-{request.Repo}/{request.ParentNumber}/{request.Number}"; + var share = new ShareClient(connectionString, _azSettings.FilesShareName); + var directory = share.GetDirectoryClient(dirName); + + var remaining = new Queue(); + remaining.Enqueue(directory); + while (remaining.Count > 0) + { + var dir = remaining.Dequeue(); + await foreach (var item in dir.GetFilesAndDirectoriesAsync()) + { + if (!item.IsDirectory && item.Name != "run.sh") // we don't want the generated script in the PR + { + try + { + var file = dir.GetFileClient(item.Name); + var filePath = file.Path.Replace($"{_azSettings.FilesShareName}/", "") + .Replace($"{dirName}/", ""); + var fileStream = await file.OpenReadAsync(); + using (var reader = new StreamReader(fileStream, Encoding.UTF8)) + { + var value = reader.ReadToEnd(); + + await _ghClient.Repository.Content.CreateFile( + request.Org, request.Repo, filePath, + new CreateFileRequest($"Commit message", value, request.Branch)); // TODO: add more meaningfull commit message + } + } + catch (Exception ex) + { + logger.LogError(ex, $"Error while uploading file {item.Name}"); + } + } + else if (item.IsDirectory) + { + remaining.Enqueue(dir.GetSubdirectoryClient(item.Name)); + } + } + } + } + + public async Task CreateBranch(CreateBranchRequest request) + { + var ghRepo = await _ghClient.Repository.Get(request.Org, request.Repo); + await _ghClient.Git.Reference.CreateBranch(request.Org, request.Repo, request.Branch, ghRepo.DefaultBranch); + } + + public async Task CreateIssue(CreateIssueRequest request) + { + var newIssue = new NewIssue($"{request.Label} chain for #{request.ParentNumber}") + { + Body = request.Input, + + }; + newIssue.Labels.Add(request.Label); + var issue = await _ghClient.Issue.Create(request.Org, request.Repo, newIssue); + var commentBody = $" - [ ] #{issue.Number} - tracks {request.Label}"; + var comment = await _ghClient.Issue.Comment.Create(request.Org, request.Repo, (int)request.ParentNumber, commentBody); + return new NewIssueResponse + { + IssueNumber = issue.Number, + CommentId = comment.Id + }; + + } + + public async Task CreatePR(CreatePRRequest request) + { + var ghRepo = await _ghClient.Repository.Get(request.Org, request.Repo); + await _ghClient.PullRequest.Create(request.Org, request.Repo, new NewPullRequest($"New app #{request.Number}", request.Branch, ghRepo.DefaultBranch)); + } + + public async Task MarkTaskComplete(MarkTaskCompleteRequest request) + { + var comment = await _ghClient.Issue.Comment.Get(request.Org, request.Repo, request.CommentId); + var updatedComment = comment.Body.Replace("[ ]", "[x]"); + await _ghClient.Issue.Comment.Update(request.Org, request.Repo, request.CommentId, updatedComment); + } + + public async Task PostComment(PostCommentRequest request) + { + await _ghClient.Issue.Comment.Create(request.Org, request.Repo, request.Number, request.Content); + } +} + +public interface IManageGithub +{ + Task CreateIssue(CreateIssueRequest request); + Task MarkTaskComplete(MarkTaskCompleteRequest request); + + Task CreatePR(CreatePRRequest request); + Task CreateBranch(CreateBranchRequest request); + Task CommitToBranch(CommitRequest request); + + Task PostComment(PostCommentRequest request); +} + +[GenerateSerializer] +public class MarkTaskCompleteRequest +{ + [Id(0)] + public string Org { get; set; } + [Id(1)] + public string Repo { get; set; } + [Id(2)] + public int CommentId { get; set; } +} +[GenerateSerializer] +public class CreateIssueRequest +{ + [Id(0)] + public string Input { get; set; } + [Id(1)] + public string Label { get; set; } + [Id(2)] + public long ParentNumber { get; set; } + [Id(3)] + public string Org { get; set; } + [Id(4)] + public string Repo { get; set; } +} + +public class CreateBranchRequest +{ + public string Org { get; set; } + public string Repo { get; set; } + public string Branch { get; set; } +} + +public class CreatePRRequest +{ + public string Org { get; set; } + public string Repo { get; set; } + public string Branch { get; set; } + public int Number { get; set; } +} + +public class PostCommentRequest +{ + public string Org { get; set; } + public string Repo { get; set; } + public string Content { get; set; } + public int Number { get; set; } +} + +[GenerateSerializer] +public class NewIssueResponse +{ + [Id(0)] + public int IssueNumber { get; set; } + [Id(1)] + public int CommentId { get; set; } +} + +[GenerateSerializer] +public class CommitRequest +{ + [Id(0)] + public string Dir { get; set; } + [Id(1)] + public string Org { get; set; } + [Id(2)] + public string Repo { get; set; } + [Id(3)] + public int ParentNumber { get; set; } + [Id(4)] + public int Number { get; set; } + [Id(5)] + public string Branch { get; set; } +} \ No newline at end of file diff --git a/skills/Chat.cs b/src/libs/skills/Chat.cs similarity index 100% rename from skills/Chat.cs rename to src/libs/skills/Chat.cs diff --git a/skills/CodeExplainer.cs b/src/libs/skills/CodeExplainer.cs similarity index 100% rename from skills/CodeExplainer.cs rename to src/libs/skills/CodeExplainer.cs diff --git a/skills/DevLead.cs b/src/libs/skills/DevLead.cs similarity index 100% rename from skills/DevLead.cs rename to src/libs/skills/DevLead.cs diff --git a/skills/Developer.cs b/src/libs/skills/Developer.cs similarity index 100% rename from skills/Developer.cs rename to src/libs/skills/Developer.cs diff --git a/skills/PM.cs b/src/libs/skills/PM.cs similarity index 100% rename from skills/PM.cs rename to src/libs/skills/PM.cs diff --git a/skills/SemanticFunctionConfig.cs b/src/libs/skills/SemanticFunctionConfig.cs similarity index 100% rename from skills/SemanticFunctionConfig.cs rename to src/libs/skills/SemanticFunctionConfig.cs diff --git a/skills/skills.csproj b/src/libs/skills/skills.csproj similarity index 100% rename from skills/skills.csproj rename to src/libs/skills/skills.csproj