Dotnet - core framework rework (rebased) (#511)
* dotnet rework * add dotnet workload update to startup * fix build * interim fixup * this is the stuff that was missing * renaming the .net classes * more build fixup * port dev-team sample WIP * add proto messages and IHandle to agents * add github variables * remove OAgents gh-flow * remove OAgents library * add .vs to gitignore --------- Co-authored-by: Kosta Petan <kostapetan@gmail.com> Co-authored-by: Ryan Sweet <rysweet@microsoft.com>
|
@ -9,4 +9,4 @@ pip install uv
|
|||
uv sync
|
||||
source .venv/bin/activate
|
||||
echo "export PATH=$PATH" >> ~/.bashrc
|
||||
popd
|
||||
popd
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
.vscode
|
||||
.vscode
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"ExpandedNodes": [
|
||||
""
|
||||
],
|
||||
"SelectedNode": "\\AGNext.sln",
|
||||
"PreviewInSolutionExplorer": false
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Version": 1,
|
||||
"WorkspaceRootPath": "C:\\Users\\kopetan\\source\\repos\\agnext\\",
|
||||
"Documents": [],
|
||||
"DocumentGroupContainers": [
|
||||
{
|
||||
"Orientation": 0,
|
||||
"VerticalTabListWidth": 256,
|
||||
"DocumentGroups": [
|
||||
{
|
||||
"DockedWidth": 200,
|
||||
"SelectedChildIndex": -1,
|
||||
"Children": [
|
||||
{
|
||||
"$type": "Bookmark",
|
||||
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -118,6 +118,10 @@ dotnet_diagnostic.CA1031.severity = silent
|
|||
# CA1056: URI-like properties should not be strings
|
||||
dotnet_diagnostic.CA1056.severity = silent
|
||||
|
||||
|
||||
# SKEXP0050: Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||
dotnet_diagnostic.SKEXP0050.severity = none
|
||||
|
||||
[*.{xml,config,*proj,nuspec,props,resx,targets,yml,tasks}]
|
||||
indent_size = 2
|
||||
|
||||
|
@ -497,12 +501,12 @@ end_of_line = crlf
|
|||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true:silent
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = false:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = false:silent
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true:silent
|
||||
dotnet_style_prefer_conditional_expression_over_return = true:silent
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_tuple_names = true:suggestion
|
||||
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
|
||||
|
|
|
@ -5,28 +5,20 @@ VisualStudioVersion = 17.0.31903.59
|
|||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{290F9824-BAD3-4703-B9B7-FE9C4BE3A1CF}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AI.Agents", "src\Microsoft.AI.Agents\Microsoft.AI.Agents.csproj", "{B0BF1CD6-34E3-4ED4-9B2A-9B8781E9BE20}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Autogen.Agents", "src\Microsoft.Autogen.Agents\Microsoft.Autogen.Agents.csproj", "{B0BF1CD6-34E3-4ED4-9B2A-9B8781E9BE20}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AI.Agents.Orleans", "src\Microsoft.AI.Agents.Orleans\Microsoft.AI.Agents.Orleans.csproj", "{A4AE4656-4919-45E2-9680-C317FBCF7693}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Autogen.Agents.Orleans", "src\Microsoft.Autogen.Agents.Orleans\Microsoft.Autogen.Agents.Orleans.csproj", "{A4AE4656-4919-45E2-9680-C317FBCF7693}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{943853E7-513D-45EA-870F-549CFC0AF8E8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "gh-flow", "gh-flow", "{E0E93575-7187-4975-8D72-6F285CD01767}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{50809508-F830-4553-9C4E-C802E0A0F690}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AI.DevTeam", "samples\gh-flow\src\Microsoft.AI.DevTeam\Microsoft.AI.DevTeam.csproj", "{79981945-61F7-4E1A-8949-7808FD75471B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "seed-memory", "samples\gh-flow\src\seed-memory\seed-memory.csproj", "{EF5DF177-F4F2-49D5-9E1C-2E37869238D8}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E6A25E68-EA75-4294-9B45-3CF2BB3B4ACD}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AI.Agents.Worker.Client", "src\Microsoft.AI.Agents.Worker.Client\Microsoft.AI.Agents.Worker.Client.csproj", "{20E5C8C3-CE40-4FC3-96F8-B4A2C51936E9}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Autogen.Agents.Worker.Client", "src\Microsoft.Autogen.Agents.Worker.Client\Microsoft.Autogen.Agents.Worker.Client.csproj", "{20E5C8C3-CE40-4FC3-96F8-B4A2C51936E9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AI.Agents.Worker.Server", "src\Microsoft.AI.Agents.Worker.Server\Microsoft.AI.Agents.Worker.Server.csproj", "{B9188ADC-D322-4B38-B3D6-95338E89C34B}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Autogen.Agents.Worker.Server", "src\Microsoft.Autogen.Agents.Worker.Server\Microsoft.Autogen.Agents.Worker.Server.csproj", "{B9188ADC-D322-4B38-B3D6-95338E89C34B}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "greeter", "greeter", "{320B05A6-4E1B-4B15-B3F6-745819D2BF22}"
|
||||
EndProject
|
||||
|
@ -38,6 +30,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greeter.AgentHost", "sample
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Greeter.AgentWorker", "samples\Greeter\Greeter.AgentWorker\Greeter.AgentWorker.csproj", "{7BA721F2-EE46-4A85-A8C8-3695C4ADF93E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dev-team", "dev-team", "{23B6B210-4515-4F7B-870E-108266B76E3F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.AgentHost", "samples\dev-team\DevTeam.AgentHost\DevTeam.AgentHost.csproj", "{AB2B3ACA-C302-4063-A56F-3F325042FB01}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.Agents", "samples\dev-team\DevTeam.Agents\DevTeam.Agents.csproj", "{01F62B2D-2EFB-4355-86EE-46AC0004F376}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.AppHost", "samples\dev-team\DevTeam.AppHost\DevTeam.AppHost.csproj", "{ED286F45-A2E3-426F-A306-720E834ACC42}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.Backend", "samples\dev-team\DevTeam.Backend\DevTeam.Backend.csproj", "{DDE8693A-6F7B-481C-A379-A9F1CC450840}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.ServiceDefaults", "samples\dev-team\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj", "{5179C606-9714-4D0E-962D-75FE32A2D6A2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DevTeam.Shared", "samples\dev-team\DevTeam.Shared\DevTeam.Shared.csproj", "{778D2B00-CE88-449D-AC52-0CAE9EA870AF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -52,14 +58,6 @@ Global
|
|||
{A4AE4656-4919-45E2-9680-C317FBCF7693}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A4AE4656-4919-45E2-9680-C317FBCF7693}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A4AE4656-4919-45E2-9680-C317FBCF7693}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{79981945-61F7-4E1A-8949-7808FD75471B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{79981945-61F7-4E1A-8949-7808FD75471B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{79981945-61F7-4E1A-8949-7808FD75471B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{79981945-61F7-4E1A-8949-7808FD75471B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{EF5DF177-F4F2-49D5-9E1C-2E37869238D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EF5DF177-F4F2-49D5-9E1C-2E37869238D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EF5DF177-F4F2-49D5-9E1C-2E37869238D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EF5DF177-F4F2-49D5-9E1C-2E37869238D8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{20E5C8C3-CE40-4FC3-96F8-B4A2C51936E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{20E5C8C3-CE40-4FC3-96F8-B4A2C51936E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{20E5C8C3-CE40-4FC3-96F8-B4A2C51936E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
@ -84,24 +82,47 @@ Global
|
|||
{7BA721F2-EE46-4A85-A8C8-3695C4ADF93E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7BA721F2-EE46-4A85-A8C8-3695C4ADF93E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7BA721F2-EE46-4A85-A8C8-3695C4ADF93E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AB2B3ACA-C302-4063-A56F-3F325042FB01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AB2B3ACA-C302-4063-A56F-3F325042FB01}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AB2B3ACA-C302-4063-A56F-3F325042FB01}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AB2B3ACA-C302-4063-A56F-3F325042FB01}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{01F62B2D-2EFB-4355-86EE-46AC0004F376}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{01F62B2D-2EFB-4355-86EE-46AC0004F376}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01F62B2D-2EFB-4355-86EE-46AC0004F376}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{01F62B2D-2EFB-4355-86EE-46AC0004F376}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ED286F45-A2E3-426F-A306-720E834ACC42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ED286F45-A2E3-426F-A306-720E834ACC42}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ED286F45-A2E3-426F-A306-720E834ACC42}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ED286F45-A2E3-426F-A306-720E834ACC42}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DDE8693A-6F7B-481C-A379-A9F1CC450840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DDE8693A-6F7B-481C-A379-A9F1CC450840}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DDE8693A-6F7B-481C-A379-A9F1CC450840}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DDE8693A-6F7B-481C-A379-A9F1CC450840}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5179C606-9714-4D0E-962D-75FE32A2D6A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5179C606-9714-4D0E-962D-75FE32A2D6A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5179C606-9714-4D0E-962D-75FE32A2D6A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5179C606-9714-4D0E-962D-75FE32A2D6A2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{778D2B00-CE88-449D-AC52-0CAE9EA870AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{778D2B00-CE88-449D-AC52-0CAE9EA870AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{778D2B00-CE88-449D-AC52-0CAE9EA870AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{778D2B00-CE88-449D-AC52-0CAE9EA870AF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{B0BF1CD6-34E3-4ED4-9B2A-9B8781E9BE20} = {290F9824-BAD3-4703-B9B7-FE9C4BE3A1CF}
|
||||
{A4AE4656-4919-45E2-9680-C317FBCF7693} = {290F9824-BAD3-4703-B9B7-FE9C4BE3A1CF}
|
||||
{E0E93575-7187-4975-8D72-6F285CD01767} = {943853E7-513D-45EA-870F-549CFC0AF8E8}
|
||||
{50809508-F830-4553-9C4E-C802E0A0F690} = {E0E93575-7187-4975-8D72-6F285CD01767}
|
||||
{79981945-61F7-4E1A-8949-7808FD75471B} = {50809508-F830-4553-9C4E-C802E0A0F690}
|
||||
{EF5DF177-F4F2-49D5-9E1C-2E37869238D8} = {943853E7-513D-45EA-870F-549CFC0AF8E8}
|
||||
{20E5C8C3-CE40-4FC3-96F8-B4A2C51936E9} = {290F9824-BAD3-4703-B9B7-FE9C4BE3A1CF}
|
||||
{B9188ADC-D322-4B38-B3D6-95338E89C34B} = {290F9824-BAD3-4703-B9B7-FE9C4BE3A1CF}
|
||||
{320B05A6-4E1B-4B15-B3F6-745819D2BF22} = {943853E7-513D-45EA-870F-549CFC0AF8E8}
|
||||
{06B30F2A-BA17-451A-81FF-E9CC9551F671} = {320B05A6-4E1B-4B15-B3F6-745819D2BF22}
|
||||
{E45990FD-85B3-44A2-8646-4AB2E868BC5F} = {320B05A6-4E1B-4B15-B3F6-745819D2BF22}
|
||||
{590BACCE-7310-4D7B-9618-46496F2EB171} = {320B05A6-4E1B-4B15-B3F6-745819D2BF22}
|
||||
{7BA721F2-EE46-4A85-A8C8-3695C4ADF93E} = {320B05A6-4E1B-4B15-B3F6-745819D2BF22}
|
||||
{23B6B210-4515-4F7B-870E-108266B76E3F} = {943853E7-513D-45EA-870F-549CFC0AF8E8}
|
||||
{AB2B3ACA-C302-4063-A56F-3F325042FB01} = {23B6B210-4515-4F7B-870E-108266B76E3F}
|
||||
{01F62B2D-2EFB-4355-86EE-46AC0004F376} = {23B6B210-4515-4F7B-870E-108266B76E3F}
|
||||
{ED286F45-A2E3-426F-A306-720E834ACC42} = {23B6B210-4515-4F7B-870E-108266B76E3F}
|
||||
{DDE8693A-6F7B-481C-A379-A9F1CC450840} = {23B6B210-4515-4F7B-870E-108266B76E3F}
|
||||
{5179C606-9714-4D0E-962D-75FE32A2D6A2} = {23B6B210-4515-4F7B-870E-108266B76E3F}
|
||||
{778D2B00-CE88-449D-AC52-0CAE9EA870AF} = {23B6B210-4515-4F7B-870E-108266B76E3F}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C9250809-2B94-4552-99DE-333E4646A16F}
|
||||
|
|
|
@ -27,9 +27,13 @@
|
|||
<PackageVersion Include="Elsa.Workflows.Core" Version="3.1.3" />
|
||||
<PackageVersion Include="Elsa.Workflows.Designer" Version="3.0.0-preview.727" />
|
||||
<PackageVersion Include="Elsa.Workflows.Management" Version="3.1.3" />
|
||||
<PackageVersion Include="Grpc.AspNetCore" Version="2.63.0" />
|
||||
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.63.0" />
|
||||
<PackageVersion Include="Grpc.Tools" Version="2.64.0" />
|
||||
<PackageVersion Include="Grpc.AspNetCore" Version="2.65.0" />
|
||||
<PackageVersion Include="Grpc.Core" Version="2.46.6" />
|
||||
<PackageVersion Include="Grpc.Net.ClientFactory" Version="2.65.0" />
|
||||
<PackageVersion Include="Grpc.Tools" Version="2.65.0" />
|
||||
<PackageVersion Include="Grpc.Net.Client" Version="2.65.0" />
|
||||
<PackageVersion Include="Google.Protobuf" Version="3.27.3" />
|
||||
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.8" />
|
||||
<PackageVersion Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.22.0" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Azure" Version="1.7.4" />
|
||||
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.AI.Agents.Worker.Server\Microsoft.AI.Agents.Worker.Server.csproj" />
|
||||
<ProjectReference Include="../../../src/Microsoft.Autogen.Agents.Worker.Server/Microsoft.Autogen.Agents.Worker.Server.csproj" />
|
||||
<ProjectReference Include="..\Greeter.ServiceDefaults\Greeter.ServiceDefaults.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
|
|
@ -5,9 +5,9 @@ using AgentId = Microsoft.AI.Agents.Worker.Client.AgentId;
|
|||
|
||||
namespace Greeter.AgentWorker;
|
||||
|
||||
public sealed class AgentClient(ILogger<AgentClient> logger, AgentWorkerRuntime runtime, DistributedContextPropagator distributedContextPropagator) : AgentBase(new ClientContext(logger, runtime, distributedContextPropagator))
|
||||
public sealed class AgentClient(ILogger<AgentClient> logger, AgentWorkerRuntime runtime, DistributedContextPropagator distributedContextPropagator, EventTypes typeRegistry) : AgentBase(new ClientContext(logger, runtime, distributedContextPropagator), typeRegistry)
|
||||
{
|
||||
public async ValueTask PublishEventAsync(Event @event) => await PublishEvent(@event);
|
||||
public async ValueTask PublishEventAsync(CloudEvent @event) => await PublishEvent(@event);
|
||||
public async ValueTask<RpcResponse> SendRequestAsync(AgentId target, string method, Dictionary<string, string> parameters) => await RequestAsync(target, method, parameters);
|
||||
|
||||
private sealed class ClientContext(ILogger<AgentClient> logger, AgentWorkerRuntime runtime, DistributedContextPropagator distributedContextPropagator) : IAgentContext
|
||||
|
@ -17,7 +17,7 @@ public sealed class AgentClient(ILogger<AgentClient> logger, AgentWorkerRuntime
|
|||
public ILogger Logger { get; } = logger;
|
||||
public DistributedContextPropagator DistributedContextPropagator { get; } = distributedContextPropagator;
|
||||
|
||||
public async ValueTask PublishEventAsync(Event @event)
|
||||
public async ValueTask PublishEventAsync(CloudEvent @event)
|
||||
{
|
||||
await runtime.PublishEvent(@event).ConfigureAwait(false);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../src/Microsoft.Autogen.Agents.Worker.Client/Microsoft.Autogen.Agents.Worker.Client.csproj" />
|
||||
<ProjectReference Include="..\Greeter.ServiceDefaults\Greeter.ServiceDefaults.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.AI.Agents.Worker.Client\Microsoft.AI.Agents.Worker.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -20,14 +20,8 @@ app.MapDefaultEndpoints();
|
|||
|
||||
app.Run();
|
||||
|
||||
internal sealed class GreetingAgent(IAgentContext context, ILogger<GreetingAgent> logger) : AgentBase(context)
|
||||
internal sealed class GreetingAgent(IAgentContext context, EventTypes typeRegistry, ILogger<GreetingAgent> logger) : AgentBase(context, typeRegistry)
|
||||
{
|
||||
protected override Task HandleEvent(Event @event)
|
||||
{
|
||||
logger.LogInformation("[{Id}] Received event: '{Event}'.", AgentId, @event);
|
||||
return base.HandleEvent(@event);
|
||||
}
|
||||
|
||||
protected override Task<RpcResponse> HandleRequest(RpcRequest request)
|
||||
{
|
||||
logger.LogInformation("[{Id}] Received request: '{Request}'.", AgentId, request);
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Autogen.Agents.Worker.Server\Microsoft.Autogen.Agents.Worker.Server.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,13 @@
|
|||
using Microsoft.AI.Agents.Worker;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.AddServiceDefaults();
|
||||
builder.AddAgentService();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapDefaultEndpoints();
|
||||
app.MapAgentService();
|
||||
|
||||
app.Run();
|
|
@ -4,8 +4,8 @@
|
|||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:59668",
|
||||
"sslPort": 44354
|
||||
"applicationUrl": "http://localhost:29747",
|
||||
"sslPort": 44348
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
|
@ -13,7 +13,7 @@
|
|||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5244",
|
||||
"applicationUrl": "http://localhost:5002",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
|||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7227;http://localhost:5244",
|
||||
"applicationUrl": "https://localhost:7240;http://localhost:5002",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
<ProjectReference Include="..\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj" />
|
||||
<ProjectReference Include="..\DevTeam.Shared\DevTeam.Shared.csproj" />
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Autogen.Agents.Worker.Client\Microsoft.Autogen.Agents.Worker.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,56 @@
|
|||
using DevTeam.Shared;
|
||||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace DevTeam.Agents;
|
||||
|
||||
[TopicSubscription("devteam")]
|
||||
public class Dev(IAgentContext context, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, ILogger<Dev> logger)
|
||||
: AiAgent<DeveloperState>(context, memory, kernel, typeRegistry), IDevelopApps,
|
||||
IHandle<CodeGenerationRequested>,
|
||||
IHandle<CodeChainClosed>
|
||||
{
|
||||
public async Task Handle(CodeGenerationRequested item)
|
||||
{
|
||||
var code = await GenerateCode(item.Ask);
|
||||
var evt = new CodeGenerated
|
||||
{
|
||||
Code = code
|
||||
}.ToCloudEvent(this.AgentId.Key);
|
||||
await PublishEvent(evt);
|
||||
}
|
||||
|
||||
public async Task Handle(CodeChainClosed item)
|
||||
{
|
||||
//TODO: Get code from state
|
||||
var lastCode = ""; // _state.State.History.Last().Message
|
||||
var evt = new CodeCreated
|
||||
{
|
||||
Code = lastCode
|
||||
}.ToCloudEvent(this.AgentId.Key);
|
||||
await PublishEvent(evt);
|
||||
}
|
||||
|
||||
public async Task<string> GenerateCode(string ask)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
|
||||
var instruction = "Consider the following architectural guidelines:!waf!";
|
||||
var enhancedContext = await AddKnowledge(instruction, "waf", context);
|
||||
return await CallFunction(DeveloperSkills.Implement, enhancedContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error generating code");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDevelopApps
|
||||
{
|
||||
public Task<string> GenerateCode(string ask);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Agents;
|
||||
public static class DeveloperSkills
|
||||
{
|
||||
public const string Implement = """
|
||||
|
@ -54,4 +54,4 @@ public static class DeveloperSkills
|
|||
Only include the points in a bullet point format and DON'T add anything outside of the bulleted list.
|
||||
Be short and concise.
|
||||
""";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
using DevTeam.Shared;
|
||||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace DevTeam.Agents;
|
||||
|
||||
[TopicSubscription("devteam")]
|
||||
public class DeveloperLead(IAgentContext context, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, ILogger<DeveloperLead> logger)
|
||||
: AiAgent<DeveloperLeadState>(context, memory, kernel, typeRegistry), ILeadDevelopers,
|
||||
IHandle<DevPlanRequested>,
|
||||
IHandle<DevPlanChainClosed>
|
||||
{
|
||||
public async Task Handle(DevPlanRequested item)
|
||||
{
|
||||
var plan = await CreatePlan(item.Ask);
|
||||
var evt = new DevPlanGenerated
|
||||
{
|
||||
Plan = plan
|
||||
}.ToCloudEvent(this.AgentId.Key);
|
||||
await PublishEvent(evt);
|
||||
}
|
||||
|
||||
public async Task Handle(DevPlanChainClosed item)
|
||||
{
|
||||
// TODO: Get plan from state
|
||||
var lastPlan = ""; // _state.State.History.Last().Message
|
||||
var evt = new DevPlanCreated
|
||||
{
|
||||
Plan = lastPlan
|
||||
}.ToCloudEvent(this.AgentId.Key);
|
||||
await PublishEvent(evt);
|
||||
}
|
||||
public async Task<string> CreatePlan(string ask)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
|
||||
var instruction = "Consider the following architectural guidelines:!waf!";
|
||||
var enhancedContext = await AddKnowledge(instruction, "waf", context);
|
||||
var settings = new OpenAIPromptExecutionSettings
|
||||
{
|
||||
ResponseFormat = "json_object",
|
||||
MaxTokens = 4096,
|
||||
Temperature = 0.8,
|
||||
TopP = 1
|
||||
};
|
||||
return await CallFunction(DevLeadSkills.Plan, enhancedContext, settings);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error creating development plan");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILeadDevelopers
|
||||
{
|
||||
public Task<string> CreatePlan(string ask);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Agents;
|
||||
public static class DevLeadSkills
|
||||
{
|
||||
public const string Plan = """
|
|
@ -1,4 +1,4 @@
|
|||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Agents;
|
||||
public static class PMSkills
|
||||
{
|
||||
public const string BootstrapProject = """
|
||||
|
@ -31,4 +31,4 @@ public static class PMSkills
|
|||
--
|
||||
Input: {{$input}}
|
||||
""";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using DevTeam.Shared;
|
||||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace DevTeam.Agents;
|
||||
|
||||
[TopicSubscription("devteam")]
|
||||
public class ProductManager(IAgentContext context, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, ILogger<ProductManager> logger)
|
||||
: AiAgent<ProductManagerState>(context, memory, kernel, typeRegistry), IManageProducts,
|
||||
IHandle<ReadmeChainClosed>,
|
||||
IHandle<ReadmeRequested>
|
||||
{
|
||||
public async Task Handle(ReadmeChainClosed item)
|
||||
{
|
||||
// TODO: Get readme from state
|
||||
var lastReadme = ""; // _state.State.History.Last().Message
|
||||
var evt= new ReadmeCreated {
|
||||
Readme = lastReadme
|
||||
}.ToCloudEvent(this.AgentId.Key);
|
||||
await PublishEvent(evt);
|
||||
}
|
||||
|
||||
public async Task Handle(ReadmeRequested item)
|
||||
{
|
||||
var readme = await CreateReadme(item.Ask);
|
||||
var evt = new ReadmeGenerated
|
||||
{
|
||||
Readme = readme
|
||||
}.ToCloudEvent(this.AgentId.Key);
|
||||
await PublishEvent(evt);
|
||||
}
|
||||
|
||||
public async Task<string> CreateReadme(string ask)
|
||||
{
|
||||
try
|
||||
{
|
||||
var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
|
||||
var instruction = "Consider the following architectural guidelines:!waf!";
|
||||
var enhancedContext = await AddKnowledge(instruction, "waf", context);
|
||||
return await CallFunction(PMSkills.Readme, enhancedContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.LogError(ex, "Error creating readme");
|
||||
return "";
|
||||
}
|
||||
}}
|
||||
|
||||
public interface IManageProducts
|
||||
{
|
||||
public Task<string> CreateReadme(string ask);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using DevTeam;
|
||||
using DevTeam.Agents;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.AddServiceDefaults();
|
||||
|
||||
builder.ConfigureSemanticKernel();
|
||||
|
||||
builder.AddAgentWorker(builder.Configuration["AGENT_HOST"]!)
|
||||
.AddAgent<Dev>(nameof(Dev))
|
||||
.AddAgent<ProductManager>(nameof(ProductManager))
|
||||
.AddAgent<DeveloperLead>(nameof(DeveloperLead));
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapDefaultEndpoints();
|
||||
|
||||
app.Run();
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:26814",
|
||||
"sslPort": 44386
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5210",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7188;http://localhost:5210",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsAspireHost>true</IsAspireHost>
|
||||
<UserSecretsId>e8874200-80ab-41e3-bb56-b5bb93974eea</UserSecretsId>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Aspire.Hosting.AppHost" />
|
||||
<PackageReference Include="Aspire.Hosting.Azure.ApplicationInsights" />
|
||||
<PackageReference Include="Aspire.Hosting.Azure.CognitiveServices" />
|
||||
<PackageReference Include="Aspire.Hosting.Orleans" />
|
||||
<PackageReference Include="Aspire.Hosting.Qdrant" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DevTeam.Backend\DevTeam.Backend.csproj" />
|
||||
<ProjectReference Include="..\DevTeam.AgentHost\DevTeam.AgentHost.csproj" />
|
||||
<ProjectReference Include="..\DevTeam.Agents\DevTeam.Agents.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,45 @@
|
|||
var builder = DistributedApplication.CreateBuilder(args);
|
||||
|
||||
builder.AddAzureProvisioning();
|
||||
|
||||
var qdrant = builder.AddQdrant("qdrant");
|
||||
|
||||
var orleans = builder.AddOrleans("orleans")
|
||||
.WithDevelopmentClustering();
|
||||
|
||||
var agentHost = builder.AddProject<Projects.DevTeam_AgentHost>("agenthost")
|
||||
.WithReference(orleans);
|
||||
var agentHostHttps = agentHost.GetEndpoint("https");
|
||||
|
||||
//TODO: pass the right variables - aca environment
|
||||
// var environmentId = builder.AddParameter("environmentId");
|
||||
// var acaSessions = builder.AddBicepTemplateString(
|
||||
// name: "aca-sessions",
|
||||
// bicepContent: BicepTemplates.Sessions
|
||||
// )
|
||||
// .WithParameter("environmentId", environmentId);
|
||||
// var acaSessionsEndpoint = acaSessions.GetOutput("endpoint");
|
||||
|
||||
builder.AddProject<Projects.DevTeam_Backend>("backend")
|
||||
.WithEnvironment("AGENT_HOST", $"{agentHostHttps.Property(EndpointProperty.Url)}")
|
||||
.WithEnvironment("Qdrant__Endpoint", $"{qdrant.Resource.HttpEndpoint.Property(EndpointProperty.Url)}")
|
||||
.WithEnvironment("Qdrant__ApiKey", $"{qdrant.Resource.ApiKeyParameter.Value}")
|
||||
.WithEnvironment("Qdrant__VectorSize", "1536")
|
||||
.WithEnvironment("OpenAI__Key", builder.Configuration["OpenAI:Key"])
|
||||
.WithEnvironment("OpenAI__Endpoint", builder.Configuration["OpenAI:Endpoint"])
|
||||
.WithEnvironment("Github__AppId", builder.Configuration["Github:AppId"])
|
||||
.WithEnvironment("Github__InstallationId", builder.Configuration["Github:InstallationId"])
|
||||
.WithEnvironment("Github__WebhookSecret", builder.Configuration["Github:WebhookSecret"])
|
||||
.WithEnvironment("Github__AppKey", builder.Configuration["Github:AppKey"]);
|
||||
//TODO: add this to the config in backend
|
||||
//.WithEnvironment("", acaSessionsEndpoint);
|
||||
|
||||
builder.AddProject<Projects.DevTeam_Agents>("dev-agents")
|
||||
.WithEnvironment("AGENT_HOST", $"{agentHostHttps.Property(EndpointProperty.Url)}")
|
||||
.WithEnvironment("Qdrant__Endpoint", $"{qdrant.Resource.HttpEndpoint.Property(EndpointProperty.Url)}")
|
||||
.WithEnvironment("Qdrant__ApiKey", $"{qdrant.Resource.ApiKeyParameter.Value}")
|
||||
.WithEnvironment("Qdrant__VectorSize", "1536")
|
||||
.WithEnvironment("OpenAI__Key", builder.Configuration["OpenAI:Key"])
|
||||
.WithEnvironment("OpenAI__Endpoint", builder.Configuration["OpenAI:Endpoint"]);
|
||||
|
||||
builder.Build().Run();
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:17090;http://localhost:15048",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21272",
|
||||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22141"
|
||||
}
|
||||
},
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:15048",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"DOTNET_ENVIRONMENT": "Development",
|
||||
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19228",
|
||||
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20242"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using System.Diagnostics;
|
||||
using Agents;
|
||||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using AgentId = Microsoft.AI.Agents.Worker.Client.AgentId;
|
||||
|
||||
namespace DevTeam.Backend;
|
||||
|
||||
// TODO: Extract this to be part of the Client
|
||||
public sealed class AgentClient(ILogger<AgentClient> logger, AgentWorkerRuntime runtime, DistributedContextPropagator distributedContextPropagator,
|
||||
[FromKeyedServices("EventTypes")] EventTypes eventTypes)
|
||||
: AgentBase(new ClientContext(logger, runtime, distributedContextPropagator), eventTypes )
|
||||
{
|
||||
public async ValueTask PublishEventAsync(CloudEvent evt) => await PublishEvent(evt);
|
||||
public async ValueTask<RpcResponse> SendRequestAsync(AgentId target, string method, Dictionary<string, string> parameters) => await RequestAsync(target, method, parameters);
|
||||
|
||||
private sealed class ClientContext(ILogger<AgentClient> logger, AgentWorkerRuntime runtime, DistributedContextPropagator distributedContextPropagator) : IAgentContext
|
||||
{
|
||||
public AgentId AgentId { get; } = new AgentId("client", Guid.NewGuid().ToString());
|
||||
public AgentBase? AgentInstance { get; set; }
|
||||
public ILogger Logger { get; } = logger;
|
||||
public DistributedContextPropagator DistributedContextPropagator { get; } = distributedContextPropagator;
|
||||
|
||||
public async ValueTask PublishEventAsync(CloudEvent @event)
|
||||
{
|
||||
await runtime.PublishEvent(@event).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask SendRequestAsync(AgentBase agent, RpcRequest request)
|
||||
{
|
||||
await runtime.SendRequest(AgentInstance!, request).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public async ValueTask SendResponseAsync(RpcRequest request, RpcResponse response)
|
||||
{
|
||||
await runtime.SendResponse(response).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
using DevTeam.Backend;
|
||||
using DevTeam.Shared;
|
||||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
|
||||
public class AzureGenie(IAgentContext context, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, IManageAzure azureService)
|
||||
: AiAgent<object>(context, memory, kernel, typeRegistry),
|
||||
IHandle<ReadmeCreated>,
|
||||
IHandle<CodeCreated>
|
||||
|
||||
{
|
||||
public async Task Handle(ReadmeCreated item)
|
||||
{
|
||||
// TODO: Not sure we need to store the files if we use ACA Sessions
|
||||
// //var data = item.ToData();
|
||||
// // await Store(data["org"], data["repo"], data.TryParseLong("parentNumber"), data.TryParseLong("issueNumber"), "readme", "md", "output", data["readme"]);
|
||||
// await PublishEvent(new Event
|
||||
// {
|
||||
// Namespace = item.Namespace,
|
||||
// Type = nameof(EventTypes.ReadmeStored),
|
||||
// Data = item.Data
|
||||
// });
|
||||
// break;
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task Handle(CodeCreated item)
|
||||
{
|
||||
// TODO: Not sure we need to store the files if we use ACA Sessions
|
||||
// //var data = item.ToData();
|
||||
// // await Store(data["org"], data["repo"], data.TryParseLong("parentNumber"), data.TryParseLong("issueNumber"), "run", "sh", "output", data["code"]);
|
||||
// // await RunInSandbox(data["org"], data["repo"], data.TryParseLong("parentNumber"), data.TryParseLong("issueNumber"));
|
||||
// await PublishEvent(new Event
|
||||
// {
|
||||
// Namespace = item.Namespace,
|
||||
// Type = nameof(EventTypes.SandboxRunCreated),
|
||||
// Data = item.Data
|
||||
// });
|
||||
// break;
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
public async Task Store(string org, string repo, long parentIssueNumber, long issueNumber, string filename, string extension, string dir, string output)
|
||||
{
|
||||
await azureService.Store(org, repo, parentIssueNumber, issueNumber, filename, extension, dir, output);
|
||||
}
|
||||
|
||||
public async Task RunInSandbox(string org, string repo, long parentIssueNumber, long issueNumber)
|
||||
{
|
||||
await azureService.RunInSandbox(org, repo, parentIssueNumber, issueNumber);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
using DevTeam;
|
||||
using System.Text.Json;
|
||||
using DevTeam.Backend;
|
||||
using DevTeam.Shared;
|
||||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
|
||||
public class Hubber(IAgentContext context, Kernel kernel, ISemanticTextMemory memory, [FromKeyedServices("EventTypes")] EventTypes typeRegistry, IManageGithub ghService)
|
||||
: AiAgent<object>(context, memory, kernel, typeRegistry),
|
||||
IHandle<NewAsk>,
|
||||
IHandle<ReadmeGenerated>,
|
||||
IHandle<DevPlanGenerated>,
|
||||
IHandle<DevPlanCreated>,
|
||||
IHandle<ReadmeStored>,
|
||||
IHandle<CodeGenerated>
|
||||
{
|
||||
public async Task Handle(NewAsk item)
|
||||
{
|
||||
var pmIssue = await CreateIssue(item.Org, item.Repo, item.Ask, "PM.Readme", item.IssueNumber);
|
||||
var devLeadIssue = await CreateIssue(item.Org, item.Repo, item.Ask, "DevLead.Plan", item.IssueNumber);
|
||||
await PostComment(item.Org, item.Repo, item.IssueNumber, $" - #{pmIssue} - tracks PM.Readme");
|
||||
await PostComment(item.Org, item.Repo, item.IssueNumber, $" - #{devLeadIssue} - tracks DevLead.Plan");
|
||||
await CreateBranch(item.Org, item.Repo, $"sk-{item.IssueNumber}");
|
||||
}
|
||||
|
||||
public async Task Handle(ReadmeGenerated item)
|
||||
{
|
||||
var contents = string.IsNullOrEmpty(item.Readme) ? "Sorry, I got tired, can you try again please? " : item.Readme;
|
||||
await PostComment(item.Org, item.Repo, item.IssueNumber, contents);
|
||||
}
|
||||
|
||||
public async Task Handle(DevPlanGenerated item)
|
||||
{
|
||||
var contents = string.IsNullOrEmpty(item.Plan) ? "Sorry, I got tired, can you try again please? " : item.Plan;
|
||||
await PostComment(item.Org, item.Repo, item.IssueNumber, contents);
|
||||
}
|
||||
|
||||
public async Task Handle(CodeGenerated item)
|
||||
{
|
||||
var contents = string.IsNullOrEmpty(item.Code) ? "Sorry, I got tired, can you try again please? " : item.Code;
|
||||
await PostComment(item.Org, item.Repo, item.IssueNumber, contents);
|
||||
}
|
||||
|
||||
public async Task Handle(DevPlanCreated item)
|
||||
{
|
||||
var plan = JsonSerializer.Deserialize<DevLeadPlan>(item.Plan);
|
||||
var prompts = plan!.Steps.SelectMany(s => s.Subtasks!.Select(st => st.Prompt));
|
||||
|
||||
foreach (var prompt in prompts)
|
||||
{
|
||||
var functionName = "Developer.Implement";
|
||||
var issue = await CreateIssue(item.Org, item.Repo, prompt!, functionName, item.IssueNumber);
|
||||
var commentBody = $" - #{issue} - tracks {functionName}";
|
||||
await PostComment(item.Org, item.Repo, item.IssueNumber, commentBody);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Handle(ReadmeStored item)
|
||||
{
|
||||
var branch = $"sk-{item.ParentNumber}";
|
||||
await CommitToBranch(item.Org, item.Repo, item.ParentNumber, item.IssueNumber, "output", branch);
|
||||
await CreatePullRequest(item.Org, item.Repo, item.ParentNumber, branch);
|
||||
}
|
||||
|
||||
public async Task<int> CreateIssue(string org, string repo, string input, string function, long parentNumber)
|
||||
{
|
||||
return await ghService.CreateIssue(org, repo, input, function, parentNumber);
|
||||
}
|
||||
public async Task PostComment(string org, string repo, long issueNumber, string comment)
|
||||
{
|
||||
await ghService.PostComment(org, repo, issueNumber, comment);
|
||||
}
|
||||
public async Task CreateBranch(string org, string repo, string branch)
|
||||
{
|
||||
await ghService.CreateBranch(org, repo, branch);
|
||||
}
|
||||
public async Task CreatePullRequest(string org, string repo, long issueNumber, string branch)
|
||||
{
|
||||
await ghService.CreatePR(org, repo, issueNumber, branch);
|
||||
}
|
||||
public async Task CommitToBranch(string org, string repo, long parentNumber, long issueNumber, string rootDir, string branch)
|
||||
{
|
||||
await ghService.CommitToBranch(org, repo, parentNumber, issueNumber, rootDir, branch);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
// TODO: Reimplement using ACA Sessions
|
||||
// using DevTeam.Events;
|
||||
// using Microsoft.AI.Agents.Abstractions;
|
||||
// using Microsoft.AI.Agents.Worker.Client;
|
||||
|
||||
// namespace DevTeam.Backend;
|
||||
|
||||
// public sealed class Sandbox : AgentBase
|
||||
// {
|
||||
// private const string ReminderName = "SandboxRunReminder";
|
||||
// private readonly IManageAzure _azService;
|
||||
// // private readonly IPersistentState<SandboxMetadata> _state;
|
||||
|
||||
// public Sandbox(IManageAzure azService)
|
||||
// {
|
||||
// _azService = azService;
|
||||
// _state = state;
|
||||
// }
|
||||
// public override async Task HandleEvent(Event item)
|
||||
// {
|
||||
// ArgumentNullException.ThrowIfNull(item);
|
||||
|
||||
// switch (item.Type)
|
||||
// {
|
||||
// case nameof(EventTypes.SandboxRunCreated):
|
||||
// {
|
||||
// var context = item.ToGithubContext();
|
||||
// await ScheduleCommitSandboxRun(context.Org, context.Repo, context.ParentNumber!.Value, context.IssueNumber);
|
||||
// break;
|
||||
// }
|
||||
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// public async Task ScheduleCommitSandboxRun(string org, string repo, long parentIssueNumber, long issueNumber)
|
||||
// {
|
||||
// await StoreState(org, repo, parentIssueNumber, issueNumber);
|
||||
// _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.Org}-{_state.State.Repo}-{_state.State.ParentIssueNumber}-{_state.State.IssueNumber}".ToUpperInvariant();
|
||||
|
||||
// if (await _azService.IsSandboxCompleted(sandboxId))
|
||||
// {
|
||||
// await _azService.DeleteSandbox(sandboxId);
|
||||
// await PublishEvent(new Event
|
||||
// {
|
||||
// Namespace = this.GetPrimaryKeyString(),
|
||||
// Type = nameof(GithubFlowEventType.SandboxRunFinished),
|
||||
// Data = new Dictionary<string, string>
|
||||
// {
|
||||
// ["org"] = _state.State.Org,
|
||||
// ["repo"] = _state.State.Repo,
|
||||
// ["issueNumber"] = _state.State.IssueNumber.ToString(),
|
||||
// ["parentNumber"] = _state.State.ParentIssueNumber.ToString()
|
||||
// }
|
||||
// });
|
||||
// await Cleanup();
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// await Cleanup();
|
||||
// }
|
||||
// }
|
||||
|
||||
// private async Task StoreState(string org, string repo, long parentIssueNumber, long issueNumber)
|
||||
// {
|
||||
// _state.State.Org = org;
|
||||
// _state.State.Repo = repo;
|
||||
// _state.State.ParentIssueNumber = parentIssueNumber;
|
||||
// _state.State.IssueNumber = issueNumber;
|
||||
// _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 string Org { get; set; } = default!;
|
||||
// public string Repo { get; set; } = default!;
|
||||
// public long ParentIssueNumber { get; set; }
|
||||
// public long IssueNumber { get; set; }
|
||||
// public bool IsCompleted { get; set; }
|
||||
// }
|
|
@ -1,49 +1,36 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Autogen.Agents.Worker.Client\Microsoft.Autogen.Agents.Worker.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<ServerGarbageCollection>true</ServerGarbageCollection>
|
||||
<ConcurrentGarbageCollection>true</ConcurrentGarbageCollection>
|
||||
<UserSecretsId>c073c86e-8483-4956-942f-331fd09172d4</UserSecretsId>
|
||||
<AnalysisMode>All</AnalysisMode>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" />
|
||||
<PackageReference Include="Octokit.Webhooks.AspNetCore" />
|
||||
<PackageReference Include="Octokit" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" />
|
||||
|
||||
<PackageReference Include="Microsoft.Orleans.Server" />
|
||||
<PackageReference Include="Microsoft.Orleans.Sdk" />
|
||||
<PackageReference Include="Microsoft.Orleans.Runtime" />
|
||||
<PackageReference Include="Microsoft.Orleans.Persistence.Cosmos" />
|
||||
<PackageReference Include="Microsoft.Orleans.Clustering.Cosmos" />
|
||||
<PackageReference Include="Microsoft.Orleans.Reminders.Cosmos" />
|
||||
<PackageReference Include="Microsoft.Orleans.Streaming.EventHubs" />
|
||||
<PackageReference Include="Microsoft.Orleans.Reminders" />
|
||||
<PackageReference Include="Microsoft.Orleans.Streaming" />
|
||||
<PackageReference Include="OrleansDashboard" />
|
||||
|
||||
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" />
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.Azure" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
|
||||
<PackageReference Include="Azure.ResourceManager.ContainerInstance" />
|
||||
<PackageReference Include="Azure.Storage.Files.Shares" />
|
||||
<PackageReference Include="Azure.Data.Tables" />
|
||||
<PackageReference Include="Azure.Identity" />
|
||||
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" />
|
||||
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\..\src\Microsoft.AI.Agents.Orleans\Microsoft.AI.Agents.Orleans.csproj" />
|
||||
<ProjectReference Include="..\DevTeam.ServiceDefaults\DevTeam.ServiceDefaults.csproj" />
|
||||
<ProjectReference Include="..\DevTeam.Shared\DevTeam.Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,72 @@
|
|||
using Microsoft.AI.Agents.Worker.Client;
|
||||
using DevTeam;
|
||||
using Microsoft.AI.DevTeam;
|
||||
using DevTeam.Backend;
|
||||
using Octokit.Webhooks;
|
||||
using Microsoft.Extensions.Options;
|
||||
using DevTeam.Options;
|
||||
using Microsoft.Extensions.Azure;
|
||||
using Azure.Identity;
|
||||
using Octokit.Webhooks.AspNetCore;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
builder.AddServiceDefaults();
|
||||
builder.ConfigureSemanticKernel();
|
||||
|
||||
builder.Services.AddHttpClient();
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
builder.AddAgentWorker(builder.Configuration["AGENT_HOST"]!)
|
||||
.AddAgent<AzureGenie>(nameof(AzureGenie))
|
||||
//.AddAgent<Sandbox>(nameof(Sandbox))
|
||||
.AddAgent<Hubber>(nameof(Hubber));
|
||||
|
||||
builder.Services.AddSingleton<AgentClient>();
|
||||
builder.Services.AddSingleton<WebhookEventProcessor, GithubWebHookProcessor>();
|
||||
builder.Services.AddSingleton<GithubAuthService>();
|
||||
builder.Services.AddSingleton<IManageAzure, AzureService>();
|
||||
builder.Services.AddSingleton<IManageGithub, GithubService>();
|
||||
|
||||
builder.Services.AddTransient(s =>
|
||||
{
|
||||
var ghOptions = s.GetRequiredService<IOptions<GithubOptions>>();
|
||||
var logger = s.GetRequiredService<ILogger<GithubAuthService>>();
|
||||
var ghService = new GithubAuthService(ghOptions, logger);
|
||||
var client = ghService.GetGitHubClient();
|
||||
return client;
|
||||
});
|
||||
|
||||
// TODO: Rework?
|
||||
builder.Services.AddOptions<GithubOptions>()
|
||||
.Configure<IConfiguration>((settings, configuration) =>
|
||||
{
|
||||
configuration.GetSection("Github").Bind(settings);
|
||||
})
|
||||
.ValidateDataAnnotations()
|
||||
.ValidateOnStart();
|
||||
|
||||
builder.Services.AddAzureClients(clientBuilder =>
|
||||
{
|
||||
clientBuilder.AddArmClient(default);
|
||||
clientBuilder.UseCredential(new DefaultAzureCredential());
|
||||
});
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
app.MapDefaultEndpoints();
|
||||
app.UseRouting()
|
||||
.UseEndpoints(endpoints =>
|
||||
{
|
||||
var ghOptions = app.Services.GetRequiredService<IOptions<GithubOptions>>().Value;
|
||||
endpoints.MapGitHubWebhooks(secret: ghOptions.WebhookSecret);
|
||||
});;
|
||||
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
|
||||
});
|
||||
|
||||
app.Run();
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"$schema": "http://json.schemastore.org/launchsettings.json",
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:37363",
|
||||
"sslPort": 44362
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "http://localhost:5125",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:7043;http://localhost:5125",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
using System.Text;
|
||||
using Azure;
|
||||
using Azure.Core;
|
||||
|
@ -6,9 +7,10 @@ using Azure.ResourceManager.ContainerInstance;
|
|||
using Azure.ResourceManager.ContainerInstance.Models;
|
||||
using Azure.ResourceManager.Resources;
|
||||
using Azure.Storage.Files.Shares;
|
||||
using DevTeam.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Backend;
|
||||
|
||||
public class AzureService : IManageAzure
|
||||
{
|
|
@ -1,11 +1,12 @@
|
|||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography;
|
||||
using DevTeam.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Octokit;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Backend;
|
||||
public class GithubAuthService
|
||||
{
|
||||
private readonly GithubOptions _githubSettings;
|
||||
|
@ -67,4 +68,4 @@ public class GithubAuthService
|
|||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
using System.Text;
|
||||
using System.Text;
|
||||
using Azure.Storage.Files.Shares;
|
||||
using DevTeam.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Octokit;
|
||||
using Octokit.Helpers;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Backend;
|
||||
|
||||
public class GithubService : IManageGithub
|
||||
{
|
||||
|
@ -248,4 +249,4 @@ public interface IManageGithub
|
|||
Task PostComment(string org, string repo, long issueNumber, string comment);
|
||||
Task<IEnumerable<FileResponse>> GetFiles(string org, string repo, string branch, Func<RepositoryContent, bool> filter);
|
||||
Task<string> GetMainLanguage(string org, string repo);
|
||||
}
|
||||
}
|
|
@ -1,25 +1,18 @@
|
|||
using System.Globalization;
|
||||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.DevTeam.Events;
|
||||
using System.Text.Json;
|
||||
using Agents;
|
||||
using Octokit.Webhooks;
|
||||
using Octokit.Webhooks.Events;
|
||||
using Octokit.Webhooks.Events.IssueComment;
|
||||
using Octokit.Webhooks.Events.Issues;
|
||||
using Octokit.Webhooks.Models;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Backend;
|
||||
|
||||
public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
||||
public sealed class GithubWebHookProcessor(ILogger<GithubWebHookProcessor> logger, AgentClient client) : WebhookEventProcessor
|
||||
{
|
||||
private readonly ILogger<GithubWebHookProcessor> _logger;
|
||||
private readonly IClusterClient _client;
|
||||
|
||||
public GithubWebHookProcessor(ILogger<GithubWebHookProcessor> logger,
|
||||
IClusterClient client, IManageGithub ghService, IManageAzure azService)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_client = client ?? throw new ArgumentNullException(nameof(client));
|
||||
}
|
||||
private readonly ILogger<GithubWebHookProcessor> _logger = logger;
|
||||
private readonly AgentClient _client = client;
|
||||
|
||||
protected override async Task ProcessIssuesWebhookAsync(WebhookHeaders headers, IssuesEvent issuesEvent, IssuesAction action)
|
||||
{
|
||||
|
@ -116,15 +109,13 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
|||
private async Task HandleClosingIssue(long issueNumber, long? parentNumber, string skillName, string functionName, string suffix, string org, string repo)
|
||||
{
|
||||
var subject = suffix + issueNumber.ToString();
|
||||
var streamProvider = _client.GetStreamProvider("StreamProvider");
|
||||
var streamId = StreamId.Create(ns: "default", key: subject);
|
||||
var stream = streamProvider.GetStream<Event>(streamId);
|
||||
|
||||
var eventType = (skillName, functionName) switch
|
||||
{
|
||||
("PM", "Readme") => nameof(GithubFlowEventType.ReadmeChainClosed),
|
||||
("DevLead", "Plan") => nameof(GithubFlowEventType.DevPlanChainClosed),
|
||||
("Developer", "Implement") => nameof(GithubFlowEventType.CodeChainClosed),
|
||||
_ => nameof(GithubFlowEventType.NewAsk)
|
||||
//("PM", "Readme") => nameof(EventTypes.ReadmeChainClosed),
|
||||
//("DevLead", "Plan") => nameof(EventTypes.DevPlanChainClosed),
|
||||
//("Developer", "Implement") => nameof(EventTypes.CodeChainClosed),
|
||||
_ => "asd"
|
||||
};
|
||||
var data = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -133,14 +124,13 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
|||
["issueNumber"] = issueNumber.ToString(),
|
||||
["parentNumber"] = (parentNumber ?? 0).ToString()
|
||||
};
|
||||
|
||||
await stream.OnNextAsync(new Event
|
||||
await _client.PublishEventAsync(new CloudEvent
|
||||
{
|
||||
Namespace = subject,
|
||||
Source = subject,
|
||||
Type = eventType,
|
||||
Subject = subject,
|
||||
Data = data
|
||||
TextData = JsonSerializer.Serialize(data),
|
||||
});
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task HandleNewAsk(long issueNumber, long? parentNumber, string skillName, string functionName, string suffix, string input, string org, string repo)
|
||||
|
@ -149,17 +139,14 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
|||
{
|
||||
_logger.LogInformation("Handling new ask");
|
||||
var subject = suffix + issueNumber.ToString();
|
||||
var streamProvider = _client.GetStreamProvider("StreamProvider");
|
||||
var streamId = StreamId.Create(Consts.MainNamespace, subject);
|
||||
var stream = streamProvider.GetStream<Event>(streamId);
|
||||
|
||||
var eventType = (skillName, functionName) switch
|
||||
{
|
||||
("Do", "It") => nameof(GithubFlowEventType.NewAsk),
|
||||
("PM", "Readme") => nameof(GithubFlowEventType.ReadmeRequested),
|
||||
("DevLead", "Plan") => nameof(GithubFlowEventType.DevPlanRequested),
|
||||
("Developer", "Implement") => nameof(GithubFlowEventType.CodeGenerationRequested),
|
||||
_ => nameof(GithubFlowEventType.NewAsk)
|
||||
//("Do", "It") => nameof(EventTypes.NewAsk),
|
||||
//("PM", "Readme") => nameof(EventTypes.ReadmeRequested),
|
||||
//("DevLead", "Plan") => nameof(EventTypes.DevPlanRequested),
|
||||
//("Developer", "Implement") => nameof(EventTypes.CodeGenerationRequested),
|
||||
_ => "nameof(EventTypes.NewAsk)"
|
||||
};
|
||||
var data = new Dictionary<string, string>
|
||||
{
|
||||
|
@ -170,12 +157,11 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
|||
{ "input", input}
|
||||
|
||||
};
|
||||
await stream.OnNextAsync(new Event
|
||||
await _client.PublishEventAsync(new CloudEvent
|
||||
{
|
||||
Namespace = subject,
|
||||
Source = subject,
|
||||
Type = eventType,
|
||||
Subject = subject,
|
||||
Data = data
|
||||
TextData = JsonSerializer.Serialize(data),
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -185,4 +171,3 @@ public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
|||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<IsAspireSharedProject>true</IsAspireSharedProject>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" />
|
||||
<PackageReference Include="Microsoft.Extensions.ServiceDiscovery" />
|
||||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" />
|
||||
<PackageReference Include="OpenTelemetry.Extensions.Hosting" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Http" />
|
||||
<PackageReference Include="OpenTelemetry.Instrumentation.Runtime" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,119 @@
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OpenTelemetry;
|
||||
using OpenTelemetry.Metrics;
|
||||
using OpenTelemetry.Trace;
|
||||
|
||||
namespace Microsoft.Extensions.Hosting;
|
||||
|
||||
// Adds common .NET Aspire services: service discovery, resilience, health checks, and OpenTelemetry.
|
||||
// This project should be referenced by each service project in your solution.
|
||||
// To learn more about using this project, see https://aka.ms/dotnet/aspire/service-defaults
|
||||
public static class Extensions
|
||||
{
|
||||
public static IHostApplicationBuilder AddServiceDefaults(this IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.ConfigureOpenTelemetry();
|
||||
|
||||
builder.AddDefaultHealthChecks();
|
||||
|
||||
builder.Services.AddServiceDiscovery();
|
||||
|
||||
builder.Services.ConfigureHttpClientDefaults(http =>
|
||||
{
|
||||
// Turn on resilience by default
|
||||
http.AddStandardResilienceHandler();
|
||||
|
||||
// Turn on service discovery by default
|
||||
http.AddServiceDiscovery();
|
||||
});
|
||||
|
||||
// Uncomment the following to restrict the allowed schemes for service discovery.
|
||||
// builder.Services.Configure<ServiceDiscoveryOptions>(options =>
|
||||
// {
|
||||
// options.AllowedSchemes = ["https"];
|
||||
// });
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostApplicationBuilder ConfigureOpenTelemetry(this IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Logging.AddOpenTelemetry(logging =>
|
||||
{
|
||||
logging.IncludeFormattedMessage = true;
|
||||
logging.IncludeScopes = true;
|
||||
});
|
||||
|
||||
builder.Services.AddOpenTelemetry()
|
||||
.WithMetrics(metrics =>
|
||||
{
|
||||
metrics.AddAspNetCoreInstrumentation()
|
||||
.AddHttpClientInstrumentation()
|
||||
.AddRuntimeInstrumentation()
|
||||
.AddMeter("Microsoft.Orleans");
|
||||
})
|
||||
.WithTracing(tracing =>
|
||||
{
|
||||
tracing.AddAspNetCoreInstrumentation()
|
||||
//.AddGrpcClientInstrumentation()
|
||||
.AddHttpClientInstrumentation()
|
||||
.AddSource("Microsoft.Orleans.Application")
|
||||
.AddSource("Starfleet.Agent");
|
||||
});
|
||||
|
||||
builder.AddOpenTelemetryExporters();
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static IHostApplicationBuilder AddOpenTelemetryExporters(this IHostApplicationBuilder builder)
|
||||
{
|
||||
var useOtlpExporter = !string.IsNullOrWhiteSpace(builder.Configuration["OTEL_EXPORTER_OTLP_ENDPOINT"]);
|
||||
|
||||
if (useOtlpExporter)
|
||||
{
|
||||
builder.Services.AddOpenTelemetry().UseOtlpExporter();
|
||||
}
|
||||
|
||||
// Uncomment the following lines to enable the Azure Monitor exporter (requires the Azure.Monitor.OpenTelemetry.AspNetCore package)
|
||||
//if (!string.IsNullOrEmpty(builder.Configuration["APPLICATIONINSIGHTS_CONNECTION_STRING"]))
|
||||
//{
|
||||
// builder.Services.AddOpenTelemetry()
|
||||
// .UseAzureMonitor();
|
||||
//}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static IHostApplicationBuilder AddDefaultHealthChecks(this IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.AddHealthChecks()
|
||||
// Add a default liveness check to ensure app is responsive
|
||||
.AddCheck("self", () => HealthCheckResult.Healthy(), ["live"]);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static WebApplication MapDefaultEndpoints(this WebApplication app)
|
||||
{
|
||||
// Adding health checks endpoints to applications in non-development environments has security implications.
|
||||
// See https://aka.ms/dotnet/aspire/healthchecks for details before enabling these endpoints in non-development environments.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
// All health checks must pass for app to be considered ready to accept traffic after starting
|
||||
app.MapHealthChecks("/health");
|
||||
|
||||
// Only health checks tagged with the "live" tag must pass for app to be considered alive
|
||||
app.MapHealthChecks("/alive", new HealthCheckOptions
|
||||
{
|
||||
Predicate = r => r.Tags.Contains("live")
|
||||
});
|
||||
}
|
||||
|
||||
return app;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\src\Microsoft.Autogen.Agents.Worker.Client\Microsoft.Autogen.Agents.Worker.Client.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Azure.AI.OpenAI" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Connectors.Qdrant" />
|
||||
<PackageReference Include="Microsoft.SemanticKernel.Plugins.Memory" />
|
||||
<PackageReference Include="Google.Protobuf" />
|
||||
<PackageReference Include="Grpc.Tools" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Protobuf Include="..\Protos\messages.proto" Link="Protos\messages.proto" />
|
||||
<Protobuf Include="..\Protos\states.proto" Link="Protos\states.proto" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -1,44 +1,31 @@
|
|||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.DevTeam.Extensions;
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Globalization;
|
||||
using Agents;
|
||||
|
||||
namespace Microsoft.AI.DevTeam.Events;
|
||||
|
||||
public enum GithubFlowEventType
|
||||
{
|
||||
NewAsk,
|
||||
ReadmeChainClosed,
|
||||
CodeChainClosed,
|
||||
CodeGenerationRequested,
|
||||
DevPlanRequested,
|
||||
ReadmeGenerated,
|
||||
DevPlanGenerated,
|
||||
CodeGenerated,
|
||||
DevPlanChainClosed,
|
||||
ReadmeRequested,
|
||||
ReadmeStored,
|
||||
SandboxRunFinished,
|
||||
ReadmeCreated,
|
||||
CodeCreated,
|
||||
DevPlanCreated,
|
||||
SandboxRunCreated
|
||||
}
|
||||
namespace DevTeam;
|
||||
|
||||
public static class EventExtensions
|
||||
{
|
||||
public static GithubContext ToGithubContext(this Event evt)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(evt);
|
||||
|
||||
var data = new Dictionary<string, string>();// JsonSerializer.Deserialize<Dictionary<string,string>>(evt.Data);
|
||||
return new GithubContext
|
||||
{
|
||||
Org = evt.Data["org"],
|
||||
Repo = evt.Data["repo"],
|
||||
IssueNumber = evt.Data.TryParseLong("issueNumber"),
|
||||
ParentNumber = evt.Data.TryParseLong("parentNumber")
|
||||
Org = data?["org"] ?? "",
|
||||
Repo = data?["repo"] ?? "",
|
||||
IssueNumber = data?.TryParseLong("issueNumber") ?? default,
|
||||
ParentNumber = data?.TryParseLong("parentNumber")
|
||||
};
|
||||
}
|
||||
|
||||
public static Dictionary<string, string> ToData(this Event evt)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(evt);
|
||||
return //JsonSerializer.Deserialize<Dictionary<string,string>>(evt.Data) ??
|
||||
new Dictionary<string, string>();
|
||||
}
|
||||
public static Dictionary<string, string> ToData(this GithubContext context)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(context);
|
||||
|
@ -61,4 +48,3 @@ public class GithubContext
|
|||
|
||||
public string Subject => $"{Org}/{Repo}/{IssueNumber}";
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
namespace DevTeam;
|
||||
public class DevLeadPlan
|
||||
{
|
||||
public required List<StepDescription> Steps { get; set; }
|
||||
}
|
||||
|
||||
public class StepDescription
|
||||
{
|
||||
public string? Description { get; set; }
|
||||
public string? Step { get; set; }
|
||||
public List<SubtaskDescription>? Subtasks { get; set; }
|
||||
}
|
||||
|
||||
public class SubtaskDescription
|
||||
{
|
||||
public string? Subtask { get; set; }
|
||||
public string? Prompt { get; set; }
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Options;
|
||||
|
||||
public class AzureOptions
|
||||
{
|
||||
|
@ -18,4 +18,4 @@ public class AzureOptions
|
|||
public required string FilesAccountKey { get; set; }
|
||||
[Required]
|
||||
public required string SandboxImage { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Options;
|
||||
public class GithubOptions
|
||||
{
|
||||
[Required]
|
||||
|
@ -11,4 +11,4 @@ public class GithubOptions
|
|||
public long InstallationId { get; set; }
|
||||
[Required]
|
||||
public required string WebhookSecret { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace DevTeam.Options;
|
||||
|
||||
public class OpenAIOptions
|
||||
{
|
||||
// Embeddings
|
||||
[Required]
|
||||
public required string EmbeddingsEndpoint { get; set; }
|
||||
[Required]
|
||||
public required string EmbeddingsApiKey { get; set; }
|
||||
[Required]
|
||||
public required string EmbeddingsDeploymentOrModelId { get; set; }
|
||||
|
||||
// Chat
|
||||
[Required]
|
||||
public required string ChatEndpoint { get; set; }
|
||||
[Required]
|
||||
public required string ChatApiKey { get; set; }
|
||||
[Required]
|
||||
public required string ChatDeploymentOrModelId { get; set; }
|
||||
|
||||
// TextToImage
|
||||
[Required]
|
||||
public required string ImageEndpoint { get; set; }
|
||||
[Required]
|
||||
public required string ImageApiKey { get; set; }
|
||||
// When using OpenAI, this is not required.
|
||||
public required string ImageDeploymentOrModelId { get; set; }
|
||||
}
|
|
@ -1,10 +1,11 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
namespace DevTeam.Options;
|
||||
public class QdrantOptions
|
||||
{
|
||||
[Required]
|
||||
public required string Endpoint { get; set; }
|
||||
[Required]
|
||||
public int VectorSize { get; set; }
|
||||
}
|
||||
public required int VectorSize { get; set; }
|
||||
public string ApiKey { get; set; } = "";
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
namespace Microsoft.AI.DevTeam.Extensions;
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
namespace DevTeam;
|
||||
|
||||
public static class ParseExtensions
|
||||
{
|
||||
public static long TryParseLong(this Dictionary<string, string> data, string key)
|
||||
public static long TryParseLong(this Dictionary<string, string> data, string key)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(data);
|
||||
|
||||
|
@ -12,4 +14,4 @@ public static class ParseExtensions
|
|||
}
|
||||
return default;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
using System.Text.Json;
|
||||
using Azure.AI.OpenAI;
|
||||
using DevTeam.Options;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Connectors.Qdrant;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace DevTeam;
|
||||
public static class SemanticKernelHostingExtensions
|
||||
{
|
||||
public static IHostApplicationBuilder ConfigureSemanticKernel(this IHostApplicationBuilder builder)
|
||||
{
|
||||
builder.Services.Configure<OpenAIOptions>(o =>
|
||||
{
|
||||
o.EmbeddingsEndpoint = o.ImageEndpoint = o.ChatEndpoint = builder.Configuration["OpenAI:Endpoint"] ?? throw new InvalidOperationException("Ensure that OpenAI:Endpoint is set in configuration");
|
||||
o.EmbeddingsApiKey = o.ImageApiKey = o.ChatApiKey = builder.Configuration["OpenAI:Key"]!;
|
||||
o.EmbeddingsDeploymentOrModelId = "text-embedding-3-large";
|
||||
o.ImageDeploymentOrModelId = "dall-e-3";
|
||||
o.ChatDeploymentOrModelId = "gpt-4o";
|
||||
});
|
||||
|
||||
builder.Services.Configure<OpenAIClientOptions>(o =>
|
||||
{
|
||||
o.Retry.NetworkTimeout = TimeSpan.FromMinutes(5);
|
||||
});
|
||||
|
||||
builder.Services.AddOptions<QdrantOptions>().Bind(builder.Configuration.GetSection("Qdrant"))
|
||||
.ValidateDataAnnotations()
|
||||
.ValidateOnStart();
|
||||
|
||||
builder.Services.Configure<JsonSerializerOptions>(options =>
|
||||
{
|
||||
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
|
||||
});
|
||||
|
||||
builder.Services.AddTransient(CreateKernel);
|
||||
builder.Services.AddTransient(CreateMemory);
|
||||
return builder;
|
||||
}
|
||||
|
||||
static ISemanticTextMemory CreateMemory(IServiceProvider provider)
|
||||
{
|
||||
var qdrantConfig = provider.GetRequiredService<IOptions<QdrantOptions>>().Value;
|
||||
var openAiConfig = provider.GetRequiredService<IOptions<OpenAIOptions>>().Value;
|
||||
var qdrantHttpClient = new HttpClient();
|
||||
if (!string.IsNullOrEmpty(qdrantConfig.ApiKey)) {
|
||||
qdrantHttpClient.DefaultRequestHeaders.Add("api-key", qdrantConfig.ApiKey);
|
||||
}
|
||||
var loggerFactory = provider.GetRequiredService<ILoggerFactory>();
|
||||
var memoryBuilder = new MemoryBuilder();
|
||||
return memoryBuilder.WithLoggerFactory(loggerFactory)
|
||||
.WithQdrantMemoryStore(qdrantHttpClient, qdrantConfig.VectorSize, qdrantConfig.Endpoint)
|
||||
.WithAzureOpenAITextEmbeddingGeneration(openAiConfig.EmbeddingsDeploymentOrModelId, openAiConfig.EmbeddingsEndpoint, openAiConfig.EmbeddingsApiKey)
|
||||
.Build();
|
||||
}
|
||||
|
||||
static Kernel CreateKernel(IServiceProvider provider)
|
||||
{
|
||||
OpenAIOptions openAiConfig = provider.GetRequiredService<IOptions<OpenAIOptions>>().Value;
|
||||
var builder = Kernel.CreateBuilder();
|
||||
|
||||
// Chat
|
||||
if (openAiConfig.ChatEndpoint.Contains(".azure", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var openAIClient = new OpenAIClient(new Uri(openAiConfig.ChatEndpoint), new Azure.AzureKeyCredential(openAiConfig.ChatApiKey));
|
||||
builder.Services.AddAzureOpenAIChatCompletion(openAiConfig.ChatDeploymentOrModelId, openAIClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
var openAIClient = new OpenAIClient(openAiConfig.ChatApiKey);
|
||||
builder.Services.AddOpenAIChatCompletion(openAiConfig.ChatDeploymentOrModelId, openAIClient);
|
||||
}
|
||||
|
||||
// Text to Image
|
||||
if (openAiConfig.ImageEndpoint.Contains(".azure", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrEmpty(openAiConfig.ImageDeploymentOrModelId);
|
||||
var openAIClient = new OpenAIClient(new Uri(openAiConfig.ImageEndpoint), new Azure.AzureKeyCredential(openAiConfig.ImageApiKey));
|
||||
builder.Services.AddAzureOpenAITextToImage(openAiConfig.ImageDeploymentOrModelId, openAIClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Services.AddOpenAITextToImage(openAiConfig.ImageApiKey, modelId: openAiConfig.ImageDeploymentOrModelId);
|
||||
}
|
||||
|
||||
// Embeddings
|
||||
if (openAiConfig.EmbeddingsEndpoint.Contains(".azure", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var openAIClient = new OpenAIClient(new Uri(openAiConfig.EmbeddingsEndpoint), new Azure.AzureKeyCredential(openAiConfig.EmbeddingsApiKey));
|
||||
builder.Services.AddAzureOpenAITextEmbeddingGeneration(openAiConfig.EmbeddingsDeploymentOrModelId, openAIClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
var openAIClient = new OpenAIClient(openAiConfig.EmbeddingsApiKey);
|
||||
builder.Services.AddOpenAITextEmbeddingGeneration(openAiConfig.EmbeddingsDeploymentOrModelId, openAIClient);
|
||||
}
|
||||
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package devteam;
|
||||
|
||||
option csharp_namespace = "DevTeam.Shared";
|
||||
|
||||
message NewAsk {
|
||||
string org = 1;
|
||||
string repo = 2;
|
||||
string ask = 3;
|
||||
int64 issue_number = 4;
|
||||
}
|
||||
|
||||
message ReadmeRequested {
|
||||
string ask = 1;
|
||||
}
|
||||
message ReadmeChainClosed {
|
||||
string ask = 1;
|
||||
}
|
||||
|
||||
message ReadmeCreated {
|
||||
string readme = 1;
|
||||
}
|
||||
|
||||
message ReadmeGenerated {
|
||||
string org = 1;
|
||||
string repo = 2;
|
||||
int64 issue_number = 3;
|
||||
string readme = 4;
|
||||
}
|
||||
|
||||
message CodeChainClosed {
|
||||
string user_id = 1;
|
||||
string user_message = 2;
|
||||
}
|
||||
|
||||
message CodeGenerationRequested {
|
||||
string ask = 1;
|
||||
}
|
||||
|
||||
message DevPlanRequested {
|
||||
string ask = 1;
|
||||
}
|
||||
|
||||
message DevPlanGenerated {
|
||||
string org = 1;
|
||||
string repo = 2;
|
||||
int64 issue_number = 3;
|
||||
string plan = 4;
|
||||
}
|
||||
|
||||
message CodeGenerated {
|
||||
string org = 1;
|
||||
string repo = 2;
|
||||
int64 issue_number = 3;
|
||||
string code = 4;
|
||||
}
|
||||
|
||||
message DevPlanChainClosed {
|
||||
string plan = 1;
|
||||
}
|
||||
|
||||
message ReadmeStored {
|
||||
string org = 1;
|
||||
string repo = 2;
|
||||
int64 issue_number = 3;
|
||||
int64 parent_number = 4;
|
||||
}
|
||||
|
||||
message SandboxRunFinished {
|
||||
string user_id = 1;
|
||||
string user_message = 2;
|
||||
}
|
||||
|
||||
message CodeCreated {
|
||||
string code = 1;
|
||||
}
|
||||
|
||||
message DevPlanCreated {
|
||||
string org = 1;
|
||||
string repo = 2;
|
||||
int64 issue_number = 3;
|
||||
string plan = 4;
|
||||
}
|
||||
|
||||
message SandboxRunCreated {
|
||||
string user_id = 1;
|
||||
string user_message = 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package devteam;
|
||||
|
||||
option csharp_namespace = "DevTeam.Shared";
|
||||
|
||||
|
||||
message DeveloperState {
|
||||
string understanding = 1;
|
||||
}
|
||||
|
||||
message DeveloperLeadState {
|
||||
string plan = 1;
|
||||
}
|
||||
|
||||
message ProductManagerState {
|
||||
string capabilities = 1;
|
||||
}
|
|
@ -67,3 +67,10 @@ graph TD;
|
|||
SRM --> SRF([SandboxRunFinished event]);
|
||||
SRF --> |Hubber| SRCC[Code files commited to branch];
|
||||
```
|
||||
|
||||
dotnet user-secrets set "OpenAI:Key" "your_key"
|
||||
dotnet user-secrets set "OpenAI:Endpoint" "https://your_endpoint.openai.azure.com/"
|
||||
dotnet user-secrets set "Github:AppId" "your_key"
|
||||
dotnet user-secrets set "Github:InstallationId" "https://your_endpoint.openai.azure.com/"
|
||||
dotnet user-secrets set "Github:WebhookSecret" "your_key"
|
||||
dotnet user-secrets set "Github:AppKey" "https://your_endpoint.openai.azure.com/"
|
|
@ -3,8 +3,6 @@
|
|||
name: ai-dev-team
|
||||
services:
|
||||
gh-flow:
|
||||
project: "src/Microsoft.AI.DevTeam"
|
||||
language: csharp
|
||||
project: "./DevTeam.AppHost/DevTeam.AppHost.csproj"
|
||||
language: dotnet
|
||||
host: containerapp
|
||||
docker:
|
||||
context: ../../../../
|
Before Width: | Height: | Size: 302 KiB After Width: | Height: | Size: 302 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 341 KiB After Width: | Height: | Size: 341 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"appManagedEnvironments": "cae-",
|
||||
"containerRegistryRegistries": "cr",
|
||||
"insightsComponents": "appi-",
|
||||
"operationalInsightsWorkspaces": "log-",
|
||||
"portalDashboards": "dash-",
|
||||
"resourcesResourceGroups": "rg-",
|
||||
"storageStorageAccounts": "st",
|
||||
"webServerFarms": "plan-",
|
||||
"webSitesFunctions": "func-",
|
||||
"appContainerApps": "ca-",
|
||||
"managedIdentityUserAssignedIdentities": "id-",
|
||||
"documentDBDatabaseAccounts":"cosmos-"
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
param accountName string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param containers array = [
|
||||
{
|
||||
name: 'reminders'
|
||||
id: 'reminders'
|
||||
partitionKey: '/id'
|
||||
}
|
||||
{
|
||||
name: 'persistence'
|
||||
id: 'persistence'
|
||||
partitionKey: '/id'
|
||||
}
|
||||
{
|
||||
name: 'clustering'
|
||||
id: 'clustering'
|
||||
partitionKey: '/id'
|
||||
}
|
||||
]
|
||||
|
||||
param databaseName string = ''
|
||||
param principalIds array = []
|
||||
|
||||
// Because databaseName is optional in main.bicep, we make sure the database name is set here.
|
||||
var defaultDatabaseName = 'Todo'
|
||||
var actualDatabaseName = !empty(databaseName) ? databaseName : defaultDatabaseName
|
||||
|
||||
module cosmos '../core/database/cosmos/sql/cosmos-sql-db.bicep' = {
|
||||
name: 'cosmos-sql'
|
||||
params: {
|
||||
accountName: accountName
|
||||
location: location
|
||||
tags: tags
|
||||
containers: containers
|
||||
databaseName: actualDatabaseName
|
||||
principalIds: principalIds
|
||||
}
|
||||
}
|
||||
|
||||
output accountName string = cosmos.outputs.accountName
|
||||
output connectionStringKey string = cosmos.outputs.connectionStringKey
|
||||
output databaseName string = cosmos.outputs.databaseName
|
||||
output endpoint string = cosmos.outputs.endpoint
|
||||
output roleDefinitionId string = cosmos.outputs.roleDefinitionId
|
|
@ -1,170 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param applicationInsightsName string
|
||||
param identityName string
|
||||
param serviceName string = 'gh-flow'
|
||||
param sandboxImage string = 'mcr.microsoft.com/dotnet/sdk:7.0'
|
||||
|
||||
|
||||
param containerAppsEnvironmentName string
|
||||
param containerRegistryName string
|
||||
param storageAccountName string
|
||||
param cosmosAccountName string
|
||||
|
||||
@secure()
|
||||
param githubAppKey string
|
||||
param githubAppId string
|
||||
param githubAppInstallationId string
|
||||
param rgName string
|
||||
param aciShare string
|
||||
param openAIServiceType string
|
||||
param openAIServiceId string
|
||||
param openAIDeploymentId string
|
||||
param openAIEmbeddingId string
|
||||
param openAIEndpoint string
|
||||
@secure()
|
||||
param openAIKey string
|
||||
param qdrantEndpoint string
|
||||
|
||||
resource ghFlowIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = {
|
||||
name: identityName
|
||||
location: location
|
||||
}
|
||||
|
||||
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = {
|
||||
name: applicationInsightsName
|
||||
}
|
||||
|
||||
resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' existing = {
|
||||
name: storageAccountName
|
||||
}
|
||||
|
||||
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = {
|
||||
name: cosmosAccountName
|
||||
}
|
||||
|
||||
var contributorRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')
|
||||
var wehbookSecret = uniqueString(resourceGroup().id)
|
||||
|
||||
resource rgContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
||||
name: guid(subscription().id, resourceGroup().id, contributorRole)
|
||||
properties: {
|
||||
roleDefinitionId: contributorRole
|
||||
principalType: 'ServicePrincipal'
|
||||
principalId: app.outputs.identityPrincipalId
|
||||
}
|
||||
}
|
||||
|
||||
module app '../core/host/container-app.bicep' = {
|
||||
name: '${serviceName}-ghflow'
|
||||
params: {
|
||||
name: name
|
||||
location: location
|
||||
tags: union(tags, { 'azd-service-name': serviceName })
|
||||
identityType: 'UserAssigned'
|
||||
identityName: ghFlowIdentity.name
|
||||
containerAppsEnvironmentName: containerAppsEnvironmentName
|
||||
containerRegistryName: containerRegistryName
|
||||
containerCpuCoreCount: '2.0'
|
||||
containerMemory: '4.0Gi'
|
||||
env: [
|
||||
{
|
||||
name: 'APPLICATIONINSIGHTS_CONNECTION_STRING'
|
||||
value: applicationInsights.properties.ConnectionString
|
||||
}
|
||||
{
|
||||
name: 'SANDBOX_IMAGE'
|
||||
value: sandboxImage
|
||||
}
|
||||
{
|
||||
name: 'GithubOptions__AppKey'
|
||||
value: githubAppKey
|
||||
}
|
||||
{
|
||||
name: 'GithubOptions__AppId'
|
||||
value: githubAppId
|
||||
}
|
||||
{
|
||||
name: 'GithubOptions__InstallationId'
|
||||
value: githubAppInstallationId
|
||||
}
|
||||
{
|
||||
name: 'GithubOptions__WebhookSecret'
|
||||
value: wehbookSecret
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__SubscriptionId'
|
||||
value: subscription().subscriptionId
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__Location'
|
||||
value: location
|
||||
}
|
||||
{
|
||||
name: 'AZURE_CLIENT_ID'
|
||||
value: ghFlowIdentity.properties.clientId
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__ContainerInstancesResourceGroup'
|
||||
value: rgName
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__FilesAccountKey'
|
||||
value: storage.listKeys().keys[0].value
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__FilesShareName'
|
||||
value: aciShare
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__FilesAccountName'
|
||||
value: storageAccountName
|
||||
}
|
||||
{
|
||||
name: 'AzureOptions__CosmosConnectionString'
|
||||
value: cosmos.listConnectionStrings().connectionStrings[0].connectionString
|
||||
}
|
||||
{
|
||||
name: 'OpenAIOptions__ServiceType'
|
||||
value: openAIServiceType
|
||||
}
|
||||
{
|
||||
name: 'OpenAIOptions__ServiceId'
|
||||
value: openAIServiceId
|
||||
}
|
||||
{
|
||||
name: 'OpenAIOptions__DeploymentOrModelId'
|
||||
value: openAIDeploymentId
|
||||
}
|
||||
{
|
||||
name: 'OpenAIOptions__EmbeddingDeploymentOrModelId'
|
||||
value: openAIEmbeddingId
|
||||
}
|
||||
{
|
||||
name: 'OpenAIOptions__Endpoint'
|
||||
value: openAIEndpoint
|
||||
}
|
||||
{
|
||||
name: 'OpenAIOptions__ApiKey'
|
||||
value: openAIKey
|
||||
}
|
||||
{
|
||||
name: 'QdrantOptions__Endpoint'
|
||||
value: qdrantEndpoint
|
||||
}
|
||||
{
|
||||
name: 'QdrantOptions__VectorSize'
|
||||
value: '1536'
|
||||
}
|
||||
]
|
||||
targetPort: 5274
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output SERVICE_TRANSLATE_API_IDENTITY_PRINCIPAL_ID string = app.outputs.identityPrincipalId
|
||||
output SERVICE_TRANSLATE_API_NAME string = app.outputs.name
|
||||
output SERVICE_TRANSLATE_API_URI string = app.outputs.uri
|
||||
output WEBHOOK_SECRET string = wehbookSecret
|
|
@ -1,37 +0,0 @@
|
|||
metadata description = 'Creates an Azure Cosmos DB account.'
|
||||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param connectionStringKey string = 'AZURE-COSMOS-CONNECTION-STRING'
|
||||
|
||||
@allowed([ 'GlobalDocumentDB', 'MongoDB', 'Parse' ])
|
||||
param kind string
|
||||
|
||||
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' = {
|
||||
name: name
|
||||
kind: kind
|
||||
location: location
|
||||
tags: tags
|
||||
properties: {
|
||||
consistencyPolicy: { defaultConsistencyLevel: 'Session' }
|
||||
locations: [
|
||||
{
|
||||
locationName: location
|
||||
failoverPriority: 0
|
||||
isZoneRedundant: false
|
||||
}
|
||||
]
|
||||
databaseAccountOfferType: 'Standard'
|
||||
enableAutomaticFailover: false
|
||||
enableMultipleWriteLocations: false
|
||||
apiProperties: (kind == 'MongoDB') ? { serverVersion: '4.0' } : {}
|
||||
capabilities: [ { name: 'EnableServerless' } ]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
output connectionStringKey string = connectionStringKey
|
||||
output endpoint string = cosmos.properties.documentEndpoint
|
||||
output id string = cosmos.id
|
||||
output name string = cosmos.name
|
|
@ -1,19 +0,0 @@
|
|||
metadata description = 'Creates an Azure Cosmos DB for NoSQL account.'
|
||||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
module cosmos '../../cosmos/cosmos-account.bicep' = {
|
||||
name: 'cosmos-account'
|
||||
params: {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
kind: 'GlobalDocumentDB'
|
||||
}
|
||||
}
|
||||
|
||||
output connectionStringKey string = cosmos.outputs.connectionStringKey
|
||||
output endpoint string = cosmos.outputs.endpoint
|
||||
output id string = cosmos.outputs.id
|
||||
output name string = cosmos.outputs.name
|
|
@ -1,72 +0,0 @@
|
|||
metadata description = 'Creates an Azure Cosmos DB for NoSQL account with a database.'
|
||||
param accountName string
|
||||
param databaseName string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param containers array = []
|
||||
param principalIds array = []
|
||||
|
||||
module cosmos 'cosmos-sql-account.bicep' = {
|
||||
name: 'cosmos-sql-account'
|
||||
params: {
|
||||
name: accountName
|
||||
location: location
|
||||
tags: tags
|
||||
}
|
||||
}
|
||||
|
||||
resource database 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2022-05-15' = {
|
||||
name: '${accountName}/${databaseName}'
|
||||
properties: {
|
||||
resource: { id: databaseName }
|
||||
}
|
||||
|
||||
resource list 'containers' = [for container in containers: {
|
||||
name: container.name
|
||||
properties: {
|
||||
resource: {
|
||||
id: container.id
|
||||
partitionKey: { paths: [ container.partitionKey ] }
|
||||
}
|
||||
options: {}
|
||||
}
|
||||
}]
|
||||
|
||||
dependsOn: [
|
||||
cosmos
|
||||
]
|
||||
}
|
||||
|
||||
module roleDefinition 'cosmos-sql-role-def.bicep' = {
|
||||
name: 'cosmos-sql-role-definition'
|
||||
params: {
|
||||
accountName: accountName
|
||||
}
|
||||
dependsOn: [
|
||||
cosmos
|
||||
database
|
||||
]
|
||||
}
|
||||
|
||||
// We need batchSize(1) here because sql role assignments have to be done sequentially
|
||||
@batchSize(1)
|
||||
module userRole 'cosmos-sql-role-assign.bicep' = [for principalId in principalIds: if (!empty(principalId)) {
|
||||
name: 'cosmos-sql-user-role-${uniqueString(principalId)}'
|
||||
params: {
|
||||
accountName: accountName
|
||||
roleDefinitionId: roleDefinition.outputs.id
|
||||
principalId: principalId
|
||||
}
|
||||
dependsOn: [
|
||||
cosmos
|
||||
database
|
||||
]
|
||||
}]
|
||||
|
||||
output accountId string = cosmos.outputs.id
|
||||
output accountName string = cosmos.outputs.name
|
||||
output connectionStringKey string = cosmos.outputs.connectionStringKey
|
||||
output databaseName string = databaseName
|
||||
output endpoint string = cosmos.outputs.endpoint
|
||||
output roleDefinitionId string = roleDefinition.outputs.id
|
|
@ -1,19 +0,0 @@
|
|||
metadata description = 'Creates a SQL role assignment under an Azure Cosmos DB account.'
|
||||
param accountName string
|
||||
|
||||
param roleDefinitionId string
|
||||
param principalId string = ''
|
||||
|
||||
resource role 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2022-05-15' = {
|
||||
parent: cosmos
|
||||
name: guid(roleDefinitionId, principalId, cosmos.id)
|
||||
properties: {
|
||||
principalId: principalId
|
||||
roleDefinitionId: roleDefinitionId
|
||||
scope: cosmos.id
|
||||
}
|
||||
}
|
||||
|
||||
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = {
|
||||
name: accountName
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
metadata description = 'Creates a SQL role definition under an Azure Cosmos DB account.'
|
||||
param accountName string
|
||||
|
||||
resource roleDefinition 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2022-08-15' = {
|
||||
parent: cosmos
|
||||
name: guid(cosmos.id, accountName, 'sql-role')
|
||||
properties: {
|
||||
assignableScopes: [
|
||||
cosmos.id
|
||||
]
|
||||
permissions: [
|
||||
{
|
||||
dataActions: [
|
||||
'Microsoft.DocumentDB/databaseAccounts/readMetadata'
|
||||
'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*'
|
||||
'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*'
|
||||
]
|
||||
notDataActions: []
|
||||
}
|
||||
]
|
||||
roleName: 'Reader Writer'
|
||||
type: 'CustomRole'
|
||||
}
|
||||
}
|
||||
|
||||
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2022-08-15' existing = {
|
||||
name: accountName
|
||||
}
|
||||
|
||||
output id string = roleDefinition.id
|
|
@ -1,64 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param sku object
|
||||
param storage object
|
||||
param administratorLogin string
|
||||
@secure()
|
||||
param administratorLoginPassword string
|
||||
param databaseNames array = []
|
||||
param allowAzureIPsFirewall bool = false
|
||||
param allowAllIPsFirewall bool = false
|
||||
param allowedSingleIPs array = []
|
||||
|
||||
// PostgreSQL version
|
||||
param version string
|
||||
|
||||
// Latest official version 2022-12-01 does not have Bicep types available
|
||||
resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-12-01' = {
|
||||
location: location
|
||||
tags: tags
|
||||
name: name
|
||||
sku: sku
|
||||
properties: {
|
||||
version: version
|
||||
administratorLogin: administratorLogin
|
||||
administratorLoginPassword: administratorLoginPassword
|
||||
storage: storage
|
||||
highAvailability: {
|
||||
mode: 'Disabled'
|
||||
}
|
||||
}
|
||||
|
||||
resource database 'databases' = [for name in databaseNames: {
|
||||
name: name
|
||||
}]
|
||||
|
||||
resource firewall_all 'firewallRules' = if (allowAllIPsFirewall) {
|
||||
name: 'allow-all-IPs'
|
||||
properties: {
|
||||
startIpAddress: '0.0.0.0'
|
||||
endIpAddress: '255.255.255.255'
|
||||
}
|
||||
}
|
||||
|
||||
resource firewall_azure 'firewallRules' = if (allowAzureIPsFirewall) {
|
||||
name: 'allow-all-azure-internal-IPs'
|
||||
properties: {
|
||||
startIpAddress: '0.0.0.0'
|
||||
endIpAddress: '0.0.0.0'
|
||||
}
|
||||
}
|
||||
|
||||
resource firewall_single 'firewallRules' = [for ip in allowedSingleIPs: {
|
||||
name: 'allow-single-${replace(ip, '.', '')}'
|
||||
properties: {
|
||||
startIpAddress: ip
|
||||
endIpAddress: ip
|
||||
}
|
||||
}]
|
||||
|
||||
}
|
||||
|
||||
output POSTGRES_DOMAIN_NAME string = postgresServer.properties.fullyQualifiedDomainName
|
|
@ -1,72 +0,0 @@
|
|||
param containerAppsEnvironmentName string
|
||||
param storageName string
|
||||
param shareName string
|
||||
param location string
|
||||
var storageAccountKey = listKeys(resourceId('Microsoft.Storage/storageAccounts', storageName), '2021-09-01').keys[0].value
|
||||
|
||||
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2022-11-01-preview' existing = {
|
||||
name: containerAppsEnvironmentName
|
||||
}
|
||||
|
||||
var mountName = 'qdrantstoragemount'
|
||||
var volumeName = 'qdrantstoragevol'
|
||||
resource qdrantstorage 'Microsoft.App/managedEnvironments/storages@2022-11-01-preview' = {
|
||||
name: '${containerAppsEnvironmentName}/${mountName}'
|
||||
properties: {
|
||||
azureFile: {
|
||||
accountName: storageName
|
||||
shareName: shareName
|
||||
accountKey: storageAccountKey
|
||||
accessMode: 'ReadWrite'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource qdrant 'Microsoft.App/containerApps@2022-11-01-preview' = {
|
||||
name: 'qdrant'
|
||||
location: location
|
||||
dependsOn:[
|
||||
qdrantstorage
|
||||
]
|
||||
properties: {
|
||||
environmentId: containerAppsEnvironment.id
|
||||
configuration: {
|
||||
ingress: {
|
||||
external: true
|
||||
targetPort: 6333
|
||||
}
|
||||
}
|
||||
template: {
|
||||
containers: [
|
||||
{
|
||||
name: 'qdrant'
|
||||
image: 'qdrant/qdrant'
|
||||
resources: {
|
||||
cpu: 1
|
||||
memory: '2Gi'
|
||||
}
|
||||
volumeMounts: [
|
||||
{
|
||||
volumeName: volumeName
|
||||
mountPath: '/qdrant/storage'
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
scale: {
|
||||
minReplicas: 1
|
||||
maxReplicas: 1
|
||||
}
|
||||
volumes: [
|
||||
{
|
||||
name: volumeName
|
||||
storageName: mountName
|
||||
storageType: 'AzureFile'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
output fqdn string = qdrant.properties.latestRevisionFqdn
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
@description('The name of the app service resource within the current resource group scope')
|
||||
param name string
|
||||
|
||||
@description('The app settings to be applied to the app service')
|
||||
@secure()
|
||||
param appSettings object
|
||||
|
||||
resource appService 'Microsoft.Web/sites@2022-03-01' existing = {
|
||||
name: name
|
||||
}
|
||||
|
||||
resource settings 'Microsoft.Web/sites/config@2022-03-01' = {
|
||||
name: 'appsettings'
|
||||
parent: appService
|
||||
properties: appSettings
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
// Reference Properties
|
||||
param applicationInsightsName string = ''
|
||||
param appServicePlanId string
|
||||
param keyVaultName string = ''
|
||||
param managedIdentity bool
|
||||
|
||||
// Runtime Properties
|
||||
@allowed([
|
||||
'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom'
|
||||
])
|
||||
param runtimeName string
|
||||
param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}'
|
||||
param runtimeVersion string
|
||||
|
||||
// Microsoft.Web/sites Properties
|
||||
param kind string = 'app,linux'
|
||||
|
||||
// Microsoft.Web/sites/config
|
||||
param allowedOrigins array = []
|
||||
param alwaysOn bool = true
|
||||
param appCommandLine string = ''
|
||||
@secure()
|
||||
param appSettings object = {}
|
||||
param clientAffinityEnabled bool = false
|
||||
param enableOryxBuild bool = contains(kind, 'linux')
|
||||
param functionAppScaleLimit int = -1
|
||||
param linuxFxVersion string = runtimeNameAndVersion
|
||||
param minimumElasticInstanceCount int = -1
|
||||
param numberOfWorkers int = -1
|
||||
param scmDoBuildDuringDeployment bool = false
|
||||
param use32BitWorkerProcess bool = false
|
||||
param ftpsState string = 'FtpsOnly'
|
||||
param healthCheckPath string = ''
|
||||
|
||||
resource appService 'Microsoft.Web/sites@2022-03-01' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
kind: kind
|
||||
properties: {
|
||||
serverFarmId: appServicePlanId
|
||||
siteConfig: {
|
||||
|
||||
alwaysOn: alwaysOn
|
||||
ftpsState: ftpsState
|
||||
minTlsVersion: '1.2'
|
||||
appCommandLine: appCommandLine
|
||||
numberOfWorkers: numberOfWorkers != -1 ? numberOfWorkers : null
|
||||
minimumElasticInstanceCount: minimumElasticInstanceCount != -1 ? minimumElasticInstanceCount : null
|
||||
use32BitWorkerProcess: use32BitWorkerProcess
|
||||
functionAppScaleLimit: functionAppScaleLimit != -1 ? functionAppScaleLimit : null
|
||||
healthCheckPath: healthCheckPath
|
||||
cors: {
|
||||
allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins)
|
||||
}
|
||||
}
|
||||
clientAffinityEnabled: clientAffinityEnabled
|
||||
httpsOnly: true
|
||||
}
|
||||
|
||||
identity: { type: managedIdentity ? 'SystemAssigned' : 'None' }
|
||||
|
||||
resource configLogs 'config' = {
|
||||
name: 'logs'
|
||||
properties: {
|
||||
applicationLogs: { fileSystem: { level: 'Verbose' } }
|
||||
detailedErrorMessages: { enabled: true }
|
||||
failedRequestsTracing: { enabled: true }
|
||||
httpLogs: { fileSystem: { enabled: true, retentionInDays: 1, retentionInMb: 35 } }
|
||||
}
|
||||
}
|
||||
|
||||
resource basicPublishingCredentialsPoliciesFtp 'basicPublishingCredentialsPolicies' = {
|
||||
name: 'ftp'
|
||||
location: location
|
||||
properties: {
|
||||
allow: false
|
||||
}
|
||||
}
|
||||
|
||||
resource basicPublishingCredentialsPoliciesScm 'basicPublishingCredentialsPolicies' = {
|
||||
name: 'scm'
|
||||
location: location
|
||||
properties: {
|
||||
allow: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module config 'appservice-appsettings.bicep' = if (!empty(appSettings)) {
|
||||
name: '${name}-appSettings'
|
||||
params: {
|
||||
name: appService.name
|
||||
appSettings: union(appSettings,
|
||||
{
|
||||
SCM_DO_BUILD_DURING_DEPLOYMENT: string(scmDoBuildDuringDeployment)
|
||||
ENABLE_ORYX_BUILD: string(enableOryxBuild)
|
||||
},
|
||||
runtimeName == 'python' && appCommandLine == '' ? { PYTHON_ENABLE_GUNICORN_MULTIWORKERS: 'true'} : {},
|
||||
!empty(applicationInsightsName) ? { APPLICATIONINSIGHTS_CONNECTION_STRING: applicationInsights.properties.ConnectionString } : {},
|
||||
!empty(keyVaultName) ? { AZURE_KEY_VAULT_ENDPOINT: keyVault.properties.vaultUri } : {})
|
||||
}
|
||||
}
|
||||
|
||||
resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = if (!(empty(keyVaultName))) {
|
||||
name: keyVaultName
|
||||
}
|
||||
|
||||
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (!empty(applicationInsightsName)) {
|
||||
name: applicationInsightsName
|
||||
}
|
||||
|
||||
output identityPrincipalId string = managedIdentity ? appService.identity.principalId : ''
|
||||
output name string = appService.name
|
||||
output uri string = 'https://${appService.properties.defaultHostName}'
|
|
@ -1,21 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param kind string = ''
|
||||
param reserved bool = true
|
||||
param sku object
|
||||
|
||||
resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
sku: sku
|
||||
kind: kind
|
||||
properties: {
|
||||
reserved: reserved
|
||||
}
|
||||
}
|
||||
|
||||
output id string = appServicePlan.id
|
||||
output name string = appServicePlan.name
|
|
@ -1,104 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
@description('The environment name for the container apps')
|
||||
param containerAppsEnvironmentName string
|
||||
|
||||
@description('The number of CPU cores allocated to a single container instance, e.g., 0.5')
|
||||
param containerCpuCoreCount string = '0.5'
|
||||
|
||||
@description('The maximum number of replicas to run. Must be at least 1.')
|
||||
@minValue(1)
|
||||
param containerMaxReplicas int = 10
|
||||
|
||||
@description('The amount of memory allocated to a single container instance, e.g., 1Gi')
|
||||
param containerMemory string = '1.0Gi'
|
||||
|
||||
@description('The minimum number of replicas to run. Must be at least 1.')
|
||||
@minValue(1)
|
||||
param containerMinReplicas int = 1
|
||||
|
||||
@description('The name of the container')
|
||||
param containerName string = 'main'
|
||||
|
||||
@description('The name of the container registry')
|
||||
param containerRegistryName string = ''
|
||||
|
||||
@allowed([ 'http', 'grpc' ])
|
||||
@description('The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC')
|
||||
param daprAppProtocol string = 'http'
|
||||
|
||||
@description('Enable or disable Dapr for the container app')
|
||||
param daprEnabled bool = false
|
||||
|
||||
@description('The Dapr app ID')
|
||||
param daprAppId string = containerName
|
||||
|
||||
@description('Specifies if the resource already exists')
|
||||
param exists bool = false
|
||||
|
||||
@description('Specifies if Ingress is enabled for the container app')
|
||||
param ingressEnabled bool = true
|
||||
|
||||
@description('The type of identity for the resource')
|
||||
@allowed([ 'None', 'SystemAssigned', 'UserAssigned' ])
|
||||
param identityType string = 'None'
|
||||
|
||||
@description('The name of the user-assigned identity')
|
||||
param identityName string = ''
|
||||
|
||||
@description('The name of the container image')
|
||||
param imageName string = ''
|
||||
|
||||
@description('The secrets required for the container')
|
||||
param secrets array = []
|
||||
|
||||
@description('The environment variables for the container')
|
||||
param env array = []
|
||||
|
||||
@description('Specifies if the resource ingress is exposed externally')
|
||||
param external bool = true
|
||||
|
||||
@description('The service binds associated with the container')
|
||||
param serviceBinds array = []
|
||||
|
||||
@description('The target port for the container')
|
||||
param targetPort int = 80
|
||||
|
||||
resource existingApp 'Microsoft.App/containerApps@2023-04-01-preview' existing = if (exists) {
|
||||
name: name
|
||||
}
|
||||
|
||||
module app 'container-app.bicep' = {
|
||||
name: '${deployment().name}-update'
|
||||
params: {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
identityType: identityType
|
||||
identityName: identityName
|
||||
ingressEnabled: ingressEnabled
|
||||
containerName: containerName
|
||||
containerAppsEnvironmentName: containerAppsEnvironmentName
|
||||
containerRegistryName: containerRegistryName
|
||||
containerCpuCoreCount: containerCpuCoreCount
|
||||
containerMemory: containerMemory
|
||||
containerMinReplicas: containerMinReplicas
|
||||
containerMaxReplicas: containerMaxReplicas
|
||||
daprEnabled: daprEnabled
|
||||
daprAppId: daprAppId
|
||||
daprAppProtocol: daprAppProtocol
|
||||
secrets: secrets
|
||||
external: external
|
||||
env: env
|
||||
imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : ''
|
||||
targetPort: targetPort
|
||||
serviceBinds: serviceBinds
|
||||
}
|
||||
}
|
||||
|
||||
output defaultDomain string = app.outputs.defaultDomain
|
||||
output imageName string = app.outputs.imageName
|
||||
output name string = app.outputs.name
|
||||
output uri string = app.outputs.uri
|
|
@ -1,161 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
@description('Allowed origins')
|
||||
param allowedOrigins array = []
|
||||
|
||||
@description('Name of the environment for container apps')
|
||||
param containerAppsEnvironmentName string
|
||||
|
||||
@description('CPU cores allocated to a single container instance, e.g., 0.5')
|
||||
param containerCpuCoreCount string = '0.5'
|
||||
|
||||
@description('The maximum number of replicas to run. Must be at least 1.')
|
||||
@minValue(1)
|
||||
param containerMaxReplicas int = 10
|
||||
|
||||
@description('Memory allocated to a single container instance, e.g., 1Gi')
|
||||
param containerMemory string = '1.0Gi'
|
||||
|
||||
@description('The minimum number of replicas to run. Must be at least 1.')
|
||||
param containerMinReplicas int = 1
|
||||
|
||||
@description('The name of the container')
|
||||
param containerName string = 'main'
|
||||
|
||||
@description('The name of the container registry')
|
||||
param containerRegistryName string = ''
|
||||
|
||||
@description('The protocol used by Dapr to connect to the app, e.g., http or grpc')
|
||||
@allowed([ 'http', 'grpc' ])
|
||||
param daprAppProtocol string = 'http'
|
||||
|
||||
@description('The Dapr app ID')
|
||||
param daprAppId string = containerName
|
||||
|
||||
@description('Enable Dapr')
|
||||
param daprEnabled bool = false
|
||||
|
||||
@description('The environment variables for the container')
|
||||
param env array = []
|
||||
|
||||
@description('Specifies if the resource ingress is exposed externally')
|
||||
param external bool = true
|
||||
|
||||
@description('The name of the user-assigned identity')
|
||||
param identityName string = ''
|
||||
|
||||
@description('The type of identity for the resource')
|
||||
@allowed([ 'None', 'SystemAssigned', 'UserAssigned' ])
|
||||
param identityType string = 'None'
|
||||
|
||||
@description('The name of the container image')
|
||||
param imageName string = ''
|
||||
|
||||
@description('Specifies if Ingress is enabled for the container app')
|
||||
param ingressEnabled bool = true
|
||||
|
||||
param revisionMode string = 'Single'
|
||||
|
||||
@description('The secrets required for the container')
|
||||
param secrets array = []
|
||||
|
||||
@description('The service binds associated with the container')
|
||||
param serviceBinds array = []
|
||||
|
||||
@description('The name of the container apps add-on to use. e.g. redis')
|
||||
param serviceType string = ''
|
||||
|
||||
@description('The target port for the container')
|
||||
param targetPort int = 80
|
||||
|
||||
resource userIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(identityName)) {
|
||||
name: identityName
|
||||
}
|
||||
|
||||
// Private registry support requires both an ACR name and a User Assigned managed identity
|
||||
var usePrivateRegistry = !empty(identityName) && !empty(containerRegistryName)
|
||||
|
||||
// Automatically set to `UserAssigned` when an `identityName` has been set
|
||||
var normalizedIdentityType = !empty(identityName) ? 'UserAssigned' : identityType
|
||||
|
||||
module containerRegistryAccess '../security/registry-access.bicep' = if (usePrivateRegistry) {
|
||||
name: '${deployment().name}-registry-access'
|
||||
params: {
|
||||
containerRegistryName: containerRegistryName
|
||||
principalId: usePrivateRegistry ? userIdentity.properties.principalId : ''
|
||||
}
|
||||
}
|
||||
|
||||
resource app 'Microsoft.App/containerApps@2023-04-01-preview' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
// It is critical that the identity is granted ACR pull access before the app is created
|
||||
// otherwise the container app will throw a provision error
|
||||
// This also forces us to use an user assigned managed identity since there would no way to
|
||||
// provide the system assigned identity with the ACR pull access before the app is created
|
||||
dependsOn: usePrivateRegistry ? [ containerRegistryAccess ] : []
|
||||
identity: {
|
||||
type: normalizedIdentityType
|
||||
userAssignedIdentities: !empty(identityName) && normalizedIdentityType == 'UserAssigned' ? { '${userIdentity.id}': {} } : null
|
||||
}
|
||||
properties: {
|
||||
managedEnvironmentId: containerAppsEnvironment.id
|
||||
configuration: {
|
||||
activeRevisionsMode: revisionMode
|
||||
ingress: ingressEnabled ? {
|
||||
external: external
|
||||
targetPort: targetPort
|
||||
transport: 'auto'
|
||||
corsPolicy: {
|
||||
allowedOrigins: union([ 'https://portal.azure.com', 'https://ms.portal.azure.com' ], allowedOrigins)
|
||||
}
|
||||
} : null
|
||||
dapr: daprEnabled ? {
|
||||
enabled: true
|
||||
appId: daprAppId
|
||||
appProtocol: daprAppProtocol
|
||||
appPort: ingressEnabled ? targetPort : 0
|
||||
} : { enabled: false }
|
||||
secrets: secrets
|
||||
service: !empty(serviceType) ? { type: serviceType } : null
|
||||
registries: usePrivateRegistry ? [
|
||||
{
|
||||
server: '${containerRegistryName}.azurecr.io'
|
||||
identity: userIdentity.id
|
||||
}
|
||||
] : []
|
||||
}
|
||||
template: {
|
||||
serviceBinds: !empty(serviceBinds) ? serviceBinds : null
|
||||
containers: [
|
||||
{
|
||||
image: !empty(imageName) ? imageName : 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
|
||||
name: containerName
|
||||
env: env
|
||||
resources: {
|
||||
cpu: json(containerCpuCoreCount)
|
||||
memory: containerMemory
|
||||
}
|
||||
}
|
||||
]
|
||||
scale: {
|
||||
minReplicas: containerMinReplicas
|
||||
maxReplicas: containerMaxReplicas
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-04-01-preview' existing = {
|
||||
name: containerAppsEnvironmentName
|
||||
}
|
||||
|
||||
output defaultDomain string = containerAppsEnvironment.properties.defaultDomain
|
||||
output identityPrincipalId string = normalizedIdentityType == 'None' ? '' : (empty(identityName) ? app.identity.principalId : userIdentity.properties.principalId)
|
||||
output imageName string = imageName
|
||||
output name string = app.name
|
||||
output serviceBind object = !empty(serviceType) ? { serviceId: app.id, name: name } : {}
|
||||
output uri string = ingressEnabled ? 'https://${app.properties.configuration.ingress.fqdn}' : ''
|
|
@ -1,40 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
@description('Name of the Application Insights resource')
|
||||
param applicationInsightsName string = ''
|
||||
|
||||
@description('Specifies if Dapr is enabled')
|
||||
param daprEnabled bool = false
|
||||
|
||||
@description('Name of the Log Analytics workspace')
|
||||
param logAnalyticsWorkspaceName string
|
||||
|
||||
resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-04-01-preview' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
properties: {
|
||||
appLogsConfiguration: {
|
||||
destination: 'log-analytics'
|
||||
logAnalyticsConfiguration: {
|
||||
customerId: logAnalyticsWorkspace.properties.customerId
|
||||
sharedKey: logAnalyticsWorkspace.listKeys().primarySharedKey
|
||||
}
|
||||
}
|
||||
daprAIInstrumentationKey: daprEnabled && !empty(applicationInsightsName) ? applicationInsights.properties.InstrumentationKey : ''
|
||||
}
|
||||
}
|
||||
|
||||
resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' existing = {
|
||||
name: logAnalyticsWorkspaceName
|
||||
}
|
||||
|
||||
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' existing = if (daprEnabled && !empty(applicationInsightsName)) {
|
||||
name: applicationInsightsName
|
||||
}
|
||||
|
||||
output defaultDomain string = containerAppsEnvironment.properties.defaultDomain
|
||||
output id string = containerAppsEnvironment.id
|
||||
output name string = containerAppsEnvironment.name
|
|
@ -1,37 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
param containerAppsEnvironmentName string
|
||||
param containerRegistryName string
|
||||
param containerRegistryResourceGroupName string = ''
|
||||
param logAnalyticsWorkspaceName string
|
||||
param applicationInsightsName string = ''
|
||||
|
||||
module containerAppsEnvironment 'container-apps-environment.bicep' = {
|
||||
name: '${name}-container-apps-environment'
|
||||
params: {
|
||||
name: containerAppsEnvironmentName
|
||||
location: location
|
||||
tags: tags
|
||||
logAnalyticsWorkspaceName: logAnalyticsWorkspaceName
|
||||
applicationInsightsName: applicationInsightsName
|
||||
}
|
||||
}
|
||||
|
||||
module containerRegistry 'container-registry.bicep' = {
|
||||
name: '${name}-container-registry'
|
||||
scope: !empty(containerRegistryResourceGroupName) ? resourceGroup(containerRegistryResourceGroupName) : resourceGroup()
|
||||
params: {
|
||||
name: containerRegistryName
|
||||
location: location
|
||||
tags: tags
|
||||
}
|
||||
}
|
||||
|
||||
output defaultDomain string = containerAppsEnvironment.outputs.defaultDomain
|
||||
output environmentName string = containerAppsEnvironment.outputs.name
|
||||
output environmentId string = containerAppsEnvironment.outputs.id
|
||||
|
||||
output registryLoginServer string = containerRegistry.outputs.loginServer
|
||||
output registryName string = containerRegistry.outputs.name
|
|
@ -1,82 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
@description('Indicates whether admin user is enabled')
|
||||
param adminUserEnabled bool = false
|
||||
|
||||
@description('Indicates whether anonymous pull is enabled')
|
||||
param anonymousPullEnabled bool = false
|
||||
|
||||
@description('Indicates whether data endpoint is enabled')
|
||||
param dataEndpointEnabled bool = false
|
||||
|
||||
@description('Encryption settings')
|
||||
param encryption object = {
|
||||
status: 'disabled'
|
||||
}
|
||||
|
||||
@description('Options for bypassing network rules')
|
||||
param networkRuleBypassOptions string = 'AzureServices'
|
||||
|
||||
@description('Public network access setting')
|
||||
param publicNetworkAccess string = 'Enabled'
|
||||
|
||||
@description('SKU settings')
|
||||
param sku object = {
|
||||
name: 'Basic'
|
||||
}
|
||||
|
||||
@description('Zone redundancy setting')
|
||||
param zoneRedundancy string = 'Disabled'
|
||||
|
||||
@description('The log analytics workspace ID used for logging and monitoring')
|
||||
param workspaceId string = ''
|
||||
|
||||
// 2022-02-01-preview needed for anonymousPullEnabled
|
||||
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
sku: sku
|
||||
properties: {
|
||||
adminUserEnabled: adminUserEnabled
|
||||
anonymousPullEnabled: anonymousPullEnabled
|
||||
dataEndpointEnabled: dataEndpointEnabled
|
||||
encryption: encryption
|
||||
networkRuleBypassOptions: networkRuleBypassOptions
|
||||
publicNetworkAccess: publicNetworkAccess
|
||||
zoneRedundancy: zoneRedundancy
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Update diagnostics to be its own module
|
||||
// Blocking issue: https://github.com/Azure/bicep/issues/622
|
||||
// Unable to pass in a `resource` scope or unable to use string interpolation in resource types
|
||||
resource diagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) {
|
||||
name: 'registry-diagnostics'
|
||||
scope: containerRegistry
|
||||
properties: {
|
||||
workspaceId: workspaceId
|
||||
logs: [
|
||||
{
|
||||
category: 'ContainerRegistryRepositoryEvents'
|
||||
enabled: true
|
||||
}
|
||||
{
|
||||
category: 'ContainerRegistryLoginEvents'
|
||||
enabled: true
|
||||
}
|
||||
]
|
||||
metrics: [
|
||||
{
|
||||
category: 'AllMetrics'
|
||||
enabled: true
|
||||
timeGrain: 'PT1M'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
output loginServer string = containerRegistry.properties.loginServer
|
||||
output name string = containerRegistry.name
|
|
@ -1,87 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
// Reference Properties
|
||||
param applicationInsightsName string = ''
|
||||
param appServicePlanId string
|
||||
param keyVaultName string = ''
|
||||
param managedIdentity bool
|
||||
param storageAccountName string
|
||||
|
||||
// Runtime Properties
|
||||
@allowed([
|
||||
'dotnet', 'dotnetcore', 'dotnet-isolated', 'node', 'python', 'java', 'powershell', 'custom'
|
||||
])
|
||||
param runtimeName string
|
||||
param runtimeNameAndVersion string = '${runtimeName}|${runtimeVersion}'
|
||||
param runtimeVersion string
|
||||
|
||||
// Function Settings
|
||||
@allowed([
|
||||
'~4', '~3', '~2', '~1'
|
||||
])
|
||||
param extensionVersion string = '~4'
|
||||
|
||||
// Microsoft.Web/sites Properties
|
||||
param kind string = 'functionapp'
|
||||
|
||||
// Microsoft.Web/sites/config
|
||||
param allowedOrigins array = []
|
||||
param alwaysOn bool = true
|
||||
param appCommandLine string = ''
|
||||
@secure()
|
||||
param appSettings object = {}
|
||||
param clientAffinityEnabled bool = false
|
||||
param enableOryxBuild bool = contains(kind, 'linux')
|
||||
param functionAppScaleLimit int = -1
|
||||
param linuxFxVersion string = runtimeNameAndVersion
|
||||
param minimumElasticInstanceCount int = -1
|
||||
param numberOfWorkers int = -1
|
||||
param scmDoBuildDuringDeployment bool = true
|
||||
param use32BitWorkerProcess bool = false
|
||||
param healthCheckPath string = ''
|
||||
|
||||
|
||||
module functions 'appservice.bicep' = {
|
||||
name: '${name}-functions'
|
||||
params: {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
allowedOrigins: allowedOrigins
|
||||
alwaysOn: alwaysOn
|
||||
appCommandLine: appCommandLine
|
||||
applicationInsightsName: applicationInsightsName
|
||||
appServicePlanId: appServicePlanId
|
||||
appSettings: union(appSettings, {
|
||||
AzureWebJobsStorage: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};AccountKey=${storage.listKeys().keys[0].value};EndpointSuffix=${environment().suffixes.storage}'
|
||||
FUNCTIONS_EXTENSION_VERSION: extensionVersion
|
||||
FUNCTIONS_WORKER_RUNTIME: runtimeName
|
||||
'AzureOptions__FilesAccountKey': storage.listKeys().keys[0].value
|
||||
})
|
||||
clientAffinityEnabled: clientAffinityEnabled
|
||||
enableOryxBuild: enableOryxBuild
|
||||
functionAppScaleLimit: functionAppScaleLimit
|
||||
healthCheckPath: healthCheckPath
|
||||
keyVaultName: keyVaultName
|
||||
kind: kind
|
||||
linuxFxVersion: linuxFxVersion
|
||||
managedIdentity: managedIdentity
|
||||
minimumElasticInstanceCount: minimumElasticInstanceCount
|
||||
numberOfWorkers: numberOfWorkers
|
||||
runtimeName: runtimeName
|
||||
runtimeVersion: runtimeVersion
|
||||
runtimeNameAndVersion: runtimeNameAndVersion
|
||||
scmDoBuildDuringDeployment: scmDoBuildDuringDeployment
|
||||
use32BitWorkerProcess: use32BitWorkerProcess
|
||||
}
|
||||
}
|
||||
|
||||
resource storage 'Microsoft.Storage/storageAccounts@2021-09-01' existing = {
|
||||
name: storageAccountName
|
||||
}
|
||||
|
||||
output identityPrincipalId string = managedIdentity ? functions.outputs.identityPrincipalId : ''
|
||||
output name string = functions.outputs.name
|
||||
output uri string = functions.outputs.uri
|
|
@ -1,30 +0,0 @@
|
|||
param name string
|
||||
param dashboardName string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
param includeDashboard bool = true
|
||||
param logAnalyticsWorkspaceId string
|
||||
|
||||
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
kind: 'web'
|
||||
properties: {
|
||||
Application_Type: 'web'
|
||||
WorkspaceResourceId: logAnalyticsWorkspaceId
|
||||
}
|
||||
}
|
||||
|
||||
module applicationInsightsDashboard 'applicationinsights-dashboard.bicep' = if (includeDashboard) {
|
||||
name: 'application-insights-dashboard'
|
||||
params: {
|
||||
name: dashboardName
|
||||
location: location
|
||||
applicationInsightsName: applicationInsights.name
|
||||
}
|
||||
}
|
||||
|
||||
output connectionString string = applicationInsights.properties.ConnectionString
|
||||
output instrumentationKey string = applicationInsights.properties.InstrumentationKey
|
||||
output name string = applicationInsights.name
|
|
@ -1,21 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
properties: any({
|
||||
retentionInDays: 30
|
||||
features: {
|
||||
searchVersion: 1
|
||||
}
|
||||
sku: {
|
||||
name: 'PerGB2018'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
output id string = logAnalytics.id
|
||||
output name string = logAnalytics.name
|
|
@ -1,33 +0,0 @@
|
|||
param logAnalyticsName string
|
||||
param applicationInsightsName string
|
||||
param applicationInsightsDashboardName string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
param includeDashboard bool = true
|
||||
|
||||
module logAnalytics 'loganalytics.bicep' = {
|
||||
name: 'loganalytics'
|
||||
params: {
|
||||
name: logAnalyticsName
|
||||
location: location
|
||||
tags: tags
|
||||
}
|
||||
}
|
||||
|
||||
module applicationInsights 'applicationinsights.bicep' = {
|
||||
name: 'applicationinsights'
|
||||
params: {
|
||||
name: applicationInsightsName
|
||||
location: location
|
||||
tags: tags
|
||||
dashboardName: applicationInsightsDashboardName
|
||||
includeDashboard: includeDashboard
|
||||
logAnalyticsWorkspaceId: logAnalytics.outputs.id
|
||||
}
|
||||
}
|
||||
|
||||
output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString
|
||||
output applicationInsightsInstrumentationKey string = applicationInsights.outputs.instrumentationKey
|
||||
output applicationInsightsName string = applicationInsights.outputs.name
|
||||
output logAnalyticsWorkspaceId string = logAnalytics.outputs.id
|
||||
output logAnalyticsWorkspaceName string = logAnalytics.outputs.name
|
|
@ -1,19 +0,0 @@
|
|||
metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.'
|
||||
param containerRegistryName string
|
||||
param principalId string
|
||||
|
||||
var acrPullRole = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')
|
||||
|
||||
resource aksAcrPull 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
|
||||
scope: containerRegistry // Use when specifying a scope that is different than the deployment scope
|
||||
name: guid(subscription().id, resourceGroup().id, principalId, acrPullRole)
|
||||
properties: {
|
||||
roleDefinitionId: acrPullRole
|
||||
principalType: 'ServicePrincipal'
|
||||
principalId: principalId
|
||||
}
|
||||
}
|
||||
|
||||
resource containerRegistry 'Microsoft.ContainerRegistry/registries@2022-02-01-preview' existing = {
|
||||
name: containerRegistryName
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
param name string
|
||||
param location string = resourceGroup().location
|
||||
param tags object = {}
|
||||
|
||||
@allowed([
|
||||
'Cool'
|
||||
'Hot'
|
||||
'Premium' ])
|
||||
param accessTier string = 'Hot'
|
||||
param allowBlobPublicAccess bool = true
|
||||
param allowCrossTenantReplication bool = true
|
||||
param allowSharedKeyAccess bool = true
|
||||
param containers array = []
|
||||
param defaultToOAuthAuthentication bool = false
|
||||
param deleteRetentionPolicy object = {}
|
||||
@allowed([ 'AzureDnsZone', 'Standard' ])
|
||||
param dnsEndpointType string = 'Standard'
|
||||
param kind string = 'StorageV2'
|
||||
param minimumTlsVersion string = 'TLS1_2'
|
||||
param networkAcls object = {
|
||||
bypass: 'AzureServices'
|
||||
defaultAction: 'Allow'
|
||||
}
|
||||
@allowed([ 'Enabled', 'Disabled' ])
|
||||
param publicNetworkAccess string = 'Enabled'
|
||||
param sku object = { name: 'Standard_LRS' }
|
||||
param fileShares array = []
|
||||
param tables array = []
|
||||
|
||||
resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = {
|
||||
name: name
|
||||
location: location
|
||||
tags: tags
|
||||
kind: kind
|
||||
sku: sku
|
||||
properties: {
|
||||
accessTier: accessTier
|
||||
allowBlobPublicAccess: allowBlobPublicAccess
|
||||
allowCrossTenantReplication: allowCrossTenantReplication
|
||||
allowSharedKeyAccess: allowSharedKeyAccess
|
||||
defaultToOAuthAuthentication: defaultToOAuthAuthentication
|
||||
dnsEndpointType: dnsEndpointType
|
||||
minimumTlsVersion: minimumTlsVersion
|
||||
networkAcls: networkAcls
|
||||
publicNetworkAccess: publicNetworkAccess
|
||||
}
|
||||
|
||||
resource blobServices 'blobServices' = if (!empty(containers)) {
|
||||
name: 'default'
|
||||
properties: {
|
||||
deleteRetentionPolicy: deleteRetentionPolicy
|
||||
}
|
||||
resource container 'containers' = [for container in containers: {
|
||||
name: container.name
|
||||
properties: {
|
||||
publicAccess: contains(container, 'publicAccess') ? container.publicAccess : 'None'
|
||||
}
|
||||
}]
|
||||
}
|
||||
resource fileServices 'fileServices' = if (!empty(fileShares)) {
|
||||
name: 'default'
|
||||
resource share 'shares' = [for fileShare in fileShares: {
|
||||
name: fileShare
|
||||
}]
|
||||
}
|
||||
|
||||
resource tableServices 'tableServices' = if (!empty(tables)) {
|
||||
name: 'default'
|
||||
resource table 'tables' = [for table in tables: {
|
||||
name: table
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
output name string = storage.name
|
||||
output primaryEndpoints object = storage.properties.primaryEndpoints
|
|
@ -1,160 +0,0 @@
|
|||
targetScope = 'subscription'
|
||||
|
||||
@minLength(1)
|
||||
@maxLength(64)
|
||||
@description('Name of the the environment which is used to generate a short unique hash used in all resources.')
|
||||
param environmentName string
|
||||
|
||||
@minLength(1)
|
||||
@description('Primary location for all resources')
|
||||
param location string
|
||||
|
||||
@secure()
|
||||
param githubAppKey string
|
||||
param githubAppId string
|
||||
param githubAppInstallationId string
|
||||
param openAIServiceType string
|
||||
param openAIServiceId string
|
||||
param openAIDeploymentId string
|
||||
param openAIEmbeddingId string
|
||||
param openAIEndpoint string
|
||||
@secure()
|
||||
param openAIKey string
|
||||
|
||||
param applicationInsightsDashboardName string = ''
|
||||
param applicationInsightsName string = ''
|
||||
param logAnalyticsName string = ''
|
||||
param resourceGroupName string = ''
|
||||
param storageAccountName string = ''
|
||||
param containerAppsEnvironmentName string = ''
|
||||
param containerRegistryName string = ''
|
||||
param ghFlowServiceName string = ''
|
||||
param cosmosAccountName string = ''
|
||||
|
||||
|
||||
var aciShare = 'acishare'
|
||||
var qdrantShare = 'qdrantshare'
|
||||
|
||||
var abbrs = loadJsonContent('./abbreviations.json')
|
||||
var resourceToken = toLower(uniqueString(subscription().id, environmentName, location))
|
||||
var tags = { 'azd-env-name': environmentName }
|
||||
|
||||
// Organize resources in a resource group
|
||||
resource rg 'Microsoft.Resources/resourceGroups@2021-04-01' = {
|
||||
name: !empty(resourceGroupName) ? resourceGroupName : '${abbrs.resourcesResourceGroups}${environmentName}'
|
||||
location: location
|
||||
tags: tags
|
||||
}
|
||||
|
||||
module storage './core/storage/storage-account.bicep' = {
|
||||
name: 'storage'
|
||||
scope: rg
|
||||
params: {
|
||||
name: !empty(storageAccountName) ? storageAccountName : '${abbrs.storageStorageAccounts}${resourceToken}'
|
||||
location: location
|
||||
tags: tags
|
||||
fileShares: [
|
||||
aciShare
|
||||
qdrantShare
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Monitor application with Azure Monitor
|
||||
module monitoring './core/monitor/monitoring.bicep' = {
|
||||
name: 'monitoring'
|
||||
scope: rg
|
||||
params: {
|
||||
location: location
|
||||
tags: tags
|
||||
logAnalyticsName: !empty(logAnalyticsName) ? logAnalyticsName : '${abbrs.operationalInsightsWorkspaces}${resourceToken}'
|
||||
applicationInsightsName: !empty(applicationInsightsName) ? applicationInsightsName : '${abbrs.insightsComponents}${resourceToken}'
|
||||
applicationInsightsDashboardName: !empty(applicationInsightsDashboardName) ? applicationInsightsDashboardName : '${abbrs.portalDashboards}${resourceToken}'
|
||||
}
|
||||
}
|
||||
|
||||
// Container apps host (including container registry)
|
||||
module containerApps './core/host/container-apps.bicep' = {
|
||||
name: 'container-apps'
|
||||
scope: rg
|
||||
params: {
|
||||
name: 'app'
|
||||
location: location
|
||||
tags: tags
|
||||
containerAppsEnvironmentName: !empty(containerAppsEnvironmentName) ? containerAppsEnvironmentName : '${abbrs.appManagedEnvironments}${resourceToken}'
|
||||
containerRegistryName: !empty(containerRegistryName) ? containerRegistryName : '${abbrs.containerRegistryRegistries}${resourceToken}'
|
||||
logAnalyticsWorkspaceName: monitoring.outputs.logAnalyticsWorkspaceName
|
||||
applicationInsightsName: monitoring.outputs.applicationInsightsName
|
||||
}
|
||||
}
|
||||
|
||||
module qdrant './core/database/qdrant/qdrant-aca.bicep' = {
|
||||
name: 'qdrant-deploy'
|
||||
scope: rg
|
||||
params: {
|
||||
location: location
|
||||
containerAppsEnvironmentName: containerApps.outputs.environmentName
|
||||
shareName: qdrantShare
|
||||
storageName: storage.outputs.name
|
||||
}
|
||||
}
|
||||
|
||||
// The application database
|
||||
module cosmos './app/db.bicep' = {
|
||||
name: 'cosmos'
|
||||
scope: rg
|
||||
params: {
|
||||
accountName: !empty(cosmosAccountName) ? cosmosAccountName : '${abbrs.documentDBDatabaseAccounts}${resourceToken}'
|
||||
databaseName: 'devteam'
|
||||
location: location
|
||||
tags: tags
|
||||
}
|
||||
}
|
||||
|
||||
module ghFlow './app/gh-flow.bicep' = {
|
||||
name: 'gh-flow'
|
||||
scope: rg
|
||||
params: {
|
||||
name: !empty(ghFlowServiceName) ? ghFlowServiceName : '${abbrs.appContainerApps}ghflow-${resourceToken}'
|
||||
location: location
|
||||
tags: tags
|
||||
identityName: '${abbrs.managedIdentityUserAssignedIdentities}ghflow-${resourceToken}'
|
||||
applicationInsightsName: monitoring.outputs.applicationInsightsName
|
||||
containerAppsEnvironmentName: containerApps.outputs.environmentName
|
||||
containerRegistryName:containerApps.outputs.registryName
|
||||
storageAccountName: storage.outputs.name
|
||||
aciShare: aciShare
|
||||
githubAppId: githubAppId
|
||||
githubAppInstallationId: githubAppInstallationId
|
||||
githubAppKey: githubAppKey
|
||||
openAIDeploymentId: openAIDeploymentId
|
||||
openAIEmbeddingId: openAIEmbeddingId
|
||||
openAIEndpoint: openAIEndpoint
|
||||
openAIKey: openAIKey
|
||||
openAIServiceId: openAIServiceId
|
||||
openAIServiceType: openAIServiceType
|
||||
qdrantEndpoint: 'https://${qdrant.outputs.fqdn}'
|
||||
rgName: rg.name
|
||||
cosmosAccountName: cosmos.outputs.accountName
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// App outputs
|
||||
output APPLICATIONINSIGHTS_CONNECTION_STRING string = monitoring.outputs.applicationInsightsConnectionString
|
||||
output AZURE_CONTAINER_ENVIRONMENT_NAME string = containerApps.outputs.environmentName
|
||||
output AZURE_CONTAINER_REGISTRY_ENDPOINT string = containerApps.outputs.registryLoginServer
|
||||
output AZURE_CONTAINER_REGISTRY_NAME string = containerApps.outputs.registryName
|
||||
output AZURE_LOCATION string = location
|
||||
output AZURE_TENANT_ID string = subscription().tenantId
|
||||
output AZURE_SUBSCRIPTION_ID string = subscription().subscriptionId
|
||||
output AZURE_RESOURCE_GROUP_NAME string = rg.name
|
||||
output AZURE_FILESHARE_NAME string = aciShare
|
||||
output AZURE_FILESHARE_ACCOUNT_NAME string = storage.outputs.name
|
||||
output QDRANT_ENDPOINT string = 'https://${qdrant.outputs.fqdn}'
|
||||
output WEBHOOK_SECRET string = ghFlow.outputs.WEBHOOK_SECRET
|
||||
|
||||
// Data outputs
|
||||
output AZURE_COSMOS_ENDPOINT string = cosmos.outputs.endpoint
|
||||
output AZURE_COSMOS_CONNECTION_STRING_KEY string = cosmos.outputs.connectionStringKey
|
||||
output AZURE_COSMOS_DATABASE_NAME string = cosmos.outputs.databaseName
|
|
@ -1,42 +0,0 @@
|
|||
{
|
||||
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
|
||||
"contentVersion": "1.0.0.0",
|
||||
"parameters": {
|
||||
"environmentName": {
|
||||
"value": "${AZURE_ENV_NAME}"
|
||||
},
|
||||
"location": {
|
||||
"value": "${AZURE_LOCATION}"
|
||||
},
|
||||
"githubAppKey": {
|
||||
"value": "${GH_APP_KEY}"
|
||||
},
|
||||
"githubAppId": {
|
||||
"value": "${GH_APP_ID}"
|
||||
},
|
||||
"githubAppInstallationId": {
|
||||
"value": "${GH_APP_INST_ID}"
|
||||
},
|
||||
"openAIServiceType": {
|
||||
"value": "${OAI_SERVICE_TYPE}"
|
||||
},
|
||||
"openAIServiceId": {
|
||||
"value": "${OAI_SERVICE_ID}"
|
||||
},
|
||||
"openAIDeploymentId": {
|
||||
"value": "${OAI_DEPLOYMENT_ID}"
|
||||
},
|
||||
"openAIEmbeddingId": {
|
||||
"value": "${OAI_EMBEDDING_ID}"
|
||||
},
|
||||
"openAIEndpoint": {
|
||||
"value": "${OAI_ENDPOINT}"
|
||||
},
|
||||
"openAIKey": {
|
||||
"value": "${OAI_KEY}"
|
||||
},
|
||||
"principalId": {
|
||||
"value": "${AZURE_PRINCIPAL_ID}"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Orleans;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
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 : AiAgent<ArchitectState>
|
||||
{
|
||||
protected override string Namespace => Consts.MainNamespace;
|
||||
public Architect([PersistentState("state", "messages")] IPersistentState<AgentState<ArchitectState>> state, ISemanticTextMemory memory, Kernel kernel)
|
||||
: base(state, memory, kernel)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task HandleEvent(Event item)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateSerializer]
|
||||
public class ArchitectState
|
||||
{
|
||||
[Id(0)]
|
||||
public string FilesTree { get; set; } = "";
|
||||
|
||||
[Id(1)]
|
||||
public string HighLevelArchitecture { get; set; } = "";
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Orleans;
|
||||
using Microsoft.AI.DevTeam.Events;
|
||||
|
||||
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)
|
||||
{
|
||||
_azureService = azureService;
|
||||
}
|
||||
|
||||
public override async Task HandleEvent(Event item)
|
||||
{
|
||||
if (item?.Type is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(item));
|
||||
}
|
||||
|
||||
switch (item.Type)
|
||||
{
|
||||
case nameof(GithubFlowEventType.ReadmeCreated):
|
||||
{
|
||||
var context = item.ToGithubContext();
|
||||
await Store(context.Org, context.Repo, context.ParentNumber ?? 0, context.IssueNumber, "readme", "md", "output", item.Data["readme"]);
|
||||
await PublishEvent(new Event
|
||||
{
|
||||
Namespace = this.GetPrimaryKeyString(),
|
||||
Type = nameof(GithubFlowEventType.ReadmeStored),
|
||||
Subject = context.Subject,
|
||||
Data = context.ToData()
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case nameof(GithubFlowEventType.CodeCreated):
|
||||
{
|
||||
var context = item.ToGithubContext();
|
||||
await Store(context.Org, context.Repo, context.ParentNumber ?? 0, context.IssueNumber, "run", "sh", "output", item.Data["code"]);
|
||||
await RunInSandbox(context.Org, context.Repo, context.ParentNumber ?? 0, context.IssueNumber);
|
||||
await PublishEvent(new Event
|
||||
{
|
||||
Namespace = this.GetPrimaryKeyString(),
|
||||
Type = nameof(GithubFlowEventType.SandboxRunCreated),
|
||||
Subject = context.Subject,
|
||||
Data = context.ToData()
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Store(string org, string repo, long parentIssueNumber, long issueNumber, string filename, string extension, string dir, string output)
|
||||
{
|
||||
await _azureService.Store(org, repo, parentIssueNumber, issueNumber, filename, extension, dir, output);
|
||||
}
|
||||
|
||||
public async Task RunInSandbox(string org, string repo, long parentIssueNumber, long issueNumber)
|
||||
{
|
||||
await _azureService.RunInSandbox(org, repo, parentIssueNumber, issueNumber);
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Orleans;
|
||||
using Microsoft.AI.DevTeam.Events;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
|
||||
[ImplicitStreamSubscription(Consts.MainNamespace)]
|
||||
public class Dev : AiAgent<DeveloperState>, IDevelopApps
|
||||
{
|
||||
protected override string Namespace => Consts.MainNamespace;
|
||||
|
||||
private readonly ILogger<Dev> _logger;
|
||||
|
||||
public Dev([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<Dev> logger)
|
||||
: base(state, memory, kernel)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override async Task HandleEvent(Event item)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(item);
|
||||
switch (item.Type)
|
||||
{
|
||||
case nameof(GithubFlowEventType.CodeGenerationRequested):
|
||||
{
|
||||
var context = item.ToGithubContext();
|
||||
var code = await GenerateCode(item.Data["input"]);
|
||||
var data = context.ToData();
|
||||
data["result"] = code;
|
||||
await PublishEvent(new Event
|
||||
{
|
||||
Namespace = this.GetPrimaryKeyString(),
|
||||
Type = nameof(GithubFlowEventType.CodeGenerated),
|
||||
Subject = context.Subject,
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case nameof(GithubFlowEventType.CodeChainClosed):
|
||||
{
|
||||
var context = item.ToGithubContext();
|
||||
var lastCode = _state.State.History.Last().Message;
|
||||
var data = context.ToData();
|
||||
data["code"] = lastCode;
|
||||
await PublishEvent(new Event
|
||||
{
|
||||
Namespace = this.GetPrimaryKeyString(),
|
||||
Type = nameof(GithubFlowEventType.CodeCreated),
|
||||
Subject = context.Subject,
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> GenerateCode(string ask)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 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) };
|
||||
var instruction = "Consider the following architectural guidelines:!waf!";
|
||||
var enhancedContext = await AddKnowledge(instruction, "waf", context);
|
||||
return await CallFunction(DeveloperSkills.Implement, enhancedContext);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error generating code");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateSerializer]
|
||||
public class DeveloperState
|
||||
{
|
||||
[Id(0)]
|
||||
public string? Understanding { get; set; }
|
||||
}
|
||||
|
||||
public interface IDevelopApps
|
||||
{
|
||||
public Task<string> GenerateCode(string ask);
|
||||
}
|
||||
|
||||
[GenerateSerializer]
|
||||
public class UnderstandingResult
|
||||
{
|
||||
[Id(0)]
|
||||
public required string NewUnderstanding { get; set; }
|
||||
[Id(1)]
|
||||
public required string Explanation { get; set; }
|
||||
}
|
|
@ -1,125 +0,0 @@
|
|||
using Microsoft.AI.Agents.Abstractions;
|
||||
using Microsoft.AI.Agents.Orleans;
|
||||
using Microsoft.AI.DevTeam.Events;
|
||||
using Microsoft.SemanticKernel;
|
||||
using Microsoft.SemanticKernel.Connectors.OpenAI;
|
||||
using Microsoft.SemanticKernel.Memory;
|
||||
|
||||
namespace Microsoft.AI.DevTeam;
|
||||
[ImplicitStreamSubscription(Consts.MainNamespace)]
|
||||
public class DeveloperLead : AiAgent<DeveloperLeadState>, ILeadDevelopers
|
||||
{
|
||||
protected override string Namespace => Consts.MainNamespace;
|
||||
private readonly ILogger<DeveloperLead> _logger;
|
||||
|
||||
public DeveloperLead([PersistentState("state", "messages")] IPersistentState<AgentState<DeveloperLeadState>> state, Kernel kernel, ISemanticTextMemory memory, ILogger<DeveloperLead> logger)
|
||||
: base(state, memory, kernel)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override async Task HandleEvent(Event item)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(item);
|
||||
|
||||
switch (item.Type)
|
||||
{
|
||||
case nameof(GithubFlowEventType.DevPlanRequested):
|
||||
{
|
||||
var context = item.ToGithubContext();
|
||||
var plan = await CreatePlan(item.Data["input"]);
|
||||
var data = context.ToData();
|
||||
data["result"] = plan;
|
||||
await PublishEvent(new Event
|
||||
{
|
||||
Namespace = this.GetPrimaryKeyString(),
|
||||
Type = nameof(GithubFlowEventType.DevPlanGenerated),
|
||||
Subject = context.Subject,
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case nameof(GithubFlowEventType.DevPlanChainClosed):
|
||||
{
|
||||
var context = item.ToGithubContext();
|
||||
var latestPlan = _state.State.History.Last().Message;
|
||||
var data = context.ToData();
|
||||
data["plan"] = latestPlan;
|
||||
await PublishEvent(new Event
|
||||
{
|
||||
Namespace = this.GetPrimaryKeyString(),
|
||||
Type = nameof(GithubFlowEventType.DevPlanCreated),
|
||||
Subject = context.Subject,
|
||||
Data = data
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
public async Task<string> CreatePlan(string ask)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: Ask the architect for the existing high level architecture
|
||||
// as well as the file structure
|
||||
var context = new KernelArguments { ["input"] = AppendChatHistory(ask) };
|
||||
var instruction = "Consider the following architectural guidelines:!waf!";
|
||||
var enhancedContext = await AddKnowledge(instruction, "waf", context);
|
||||
var settings = new OpenAIPromptExecutionSettings
|
||||
{
|
||||
ResponseFormat = "json_object",
|
||||
MaxTokens = 4096,
|
||||
Temperature = 0.8,
|
||||
TopP = 1
|
||||
};
|
||||
return await CallFunction(DevLeadSkills.Plan, enhancedContext, settings);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error creating development plan");
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILeadDevelopers
|
||||
{
|
||||
public Task<string> CreatePlan(string ask);
|
||||
}
|
||||
|
||||
[GenerateSerializer]
|
||||
public class DevLeadPlanResponse
|
||||
{
|
||||
[Id(0)]
|
||||
public required List<StepDescription> Steps { get; set; }
|
||||
}
|
||||
|
||||
[GenerateSerializer]
|
||||
public class StepDescription
|
||||
{
|
||||
[Id(0)]
|
||||
public string? Description { get; set; }
|
||||
[Id(1)]
|
||||
public string? Step { get; set; }
|
||||
[Id(2)]
|
||||
public List<SubtaskDescription>? Subtasks { get; set; }
|
||||
}
|
||||
|
||||
[GenerateSerializer]
|
||||
public class SubtaskDescription
|
||||
{
|
||||
[Id(0)]
|
||||
public string? Subtask { get; set; }
|
||||
|
||||
[Id(1)]
|
||||
public string? Prompt { get; set; }
|
||||
}
|
||||
|
||||
public class DeveloperLeadState
|
||||
{
|
||||
public string? Plan { get; set; }
|
||||
}
|