refactor (not building) WIP

This commit is contained in:
Kosta Petan
2024-02-22 10:32:46 +01:00
parent f6865d8acd
commit b0e642e383
9 changed files with 114 additions and 223 deletions

View File

@@ -8,40 +8,21 @@ public class Conductor : Grain, IOrchestrateWorkflows
{
private readonly IManageGithub _ghService;
public Conductor( IManageGithub ghService)
public Conductor(IManageGithub ghService)
{
_ghService = ghService;
}
public async Task InitialFlow(string input, string org, string repo, long parentNumber)
{
await _ghService.CreateBranch(new CreateBranchRequest
{
Org = org,
Repo = repo,
Branch = $"sk-{parentNumber}"
});
var pmIssue = await _ghService.CreateIssue(new CreateIssueRequest
{
Label = $"{nameof(PM)}.{nameof(PM.Readme)}",
Org = org,
Repo = repo,
Input = input,
ParentNumber = parentNumber
});
var devLeadIssue = await _ghService.CreateIssue(new CreateIssueRequest
{
Label = $"{nameof(DevLead)}.{nameof(DevLead.Plan)}",
Org = org,
Repo = repo,
Input = input,
ParentNumber = parentNumber
});
var suffix = $"{org}-{repo}";
var lookup = GrainFactory.GetGrain<ILookupMetadata>(suffix);
var metadataList = new List<StoreMetadataPairs>{
public async Task InitialFlow(string input, string org, string repo, long parentNumber)
{
await _ghService.CreateBranch(org, repo, $"sk-{parentNumber}");
var pmIssue = await _ghService.CreateIssue(org, repo, input, $"{nameof(PM)}.{nameof(PM.Readme)}", parentNumber);
var devLeadIssue = await _ghService.CreateIssue(org, repo, input, $"{nameof(DevLead)}.{nameof(DevLead.Plan)}", parentNumber);
var suffix = $"{org}-{repo}";
var lookup = GrainFactory.GetGrain<ILookupMetadata>(suffix);
var metadataList = new List<StoreMetadataPairs>{
new StoreMetadataPairs
{
Key = pmIssue.IssueNumber,
@@ -53,9 +34,9 @@ public class Conductor : Grain, IOrchestrateWorkflows
Value = new NewIssueResponse { CommentId = devLeadIssue.CommentId, IssueNumber = (int)parentNumber}
}
};
await lookup.StoreMetadata(metadataList);
// await githubActor.CreatePR(); // TODO: this should happen when all tasks are done?
await lookup.StoreMetadata(metadataList);
// await githubActor.CreatePR(); // TODO: this should happen when all tasks are done?
}
public async Task ImplementationFlow(DevLeadPlanResponse plan, string org, string repo, int parentNumber)
{
@@ -63,20 +44,13 @@ public class Conductor : Grain, IOrchestrateWorkflows
var prompts = plan.steps.SelectMany(s => s.subtasks.Select(st => st.prompt));
var lookup = GrainFactory.GetGrain<ILookupMetadata>(suffix);
var metadataList = new List<StoreMetadataPairs>();
foreach(var prompt in prompts)
foreach (var prompt in prompts)
{
var issue = await _ghService.CreateIssue(new CreateIssueRequest
{
Label = $"{nameof(Developer)}.{nameof(Developer.Implement)}",
Org = org,
Repo = repo,
Input = prompt,
ParentNumber = parentNumber
});
var issue = await _ghService.CreateIssue(org, repo, prompt, $"{nameof(Developer)}.{nameof(Developer.Implement)}", parentNumber);
metadataList.Add(new StoreMetadataPairs
{
Key = issue.IssueNumber,
Value = new NewIssueResponse { CommentId = issue.CommentId, IssueNumber = (int)parentNumber}
Value = new NewIssueResponse { CommentId = issue.CommentId, IssueNumber = (int)parentNumber }
});
}
await lookup.StoreMetadata(metadataList);

View File

@@ -38,14 +38,8 @@ public class DeveloperLead : SemanticPersona
public async Task CreateIssue(string org, string repo, long parentNumber, string input)
{
var devLeadIssue = await _ghService.CreateIssue(new CreateIssueRequest
{
Label = $"{nameof(DevLead)}.{nameof(DevLead.Plan)}",
Org = org,
Repo = repo,
Input = input,
ParentNumber = parentNumber
});
var function = $"{nameof(DevLead)}.{nameof(DevLead.Plan)}";
var devLeadIssue = await _ghService.CreateIssue(org, repo, input, function, parentNumber);
_state.State.ParentIssueNumber = parentNumber;
_state.State.CommentId = devLeadIssue.CommentId;
@@ -109,12 +103,12 @@ public class DeveloperLead : SemanticPersona
Task.WaitAll(eventTasks.ToArray());
//await conductor.ImplementationFlow(plan, org, repo, parentIssue.IssueNumber);
await _ghService.MarkTaskComplete(new MarkTaskCompleteRequest
{
Org = org,
Repo = repo,
CommentId = _state.State.CommentId
});
// await _ghService.MarkTaskComplete(new MarkTaskCompleteRequest
// {
// Org = org,
// Repo = repo,
// CommentId = _state.State.CommentId
// });
}
public Task<DevLeadPlanResponse> GetLatestPlan()

View File

@@ -30,15 +30,9 @@ public class Dev : SemanticPersona
public async Task CreateIssue(string org, string repo, long parentNumber, string input)
{
var devIssue = await _ghService.CreateIssue(new CreateIssueRequest
{
Label = $"{nameof(Developer)}.{nameof(Developer.Implement)}",
Org = org,
Repo = repo,
Input = input,
ParentNumber = parentNumber
});
var function = $"{nameof(Developer)}.{nameof(Developer.Implement)}";
var devIssue = await _ghService.CreateIssue(org, repo, input, function, parentNumber);
_state.State.ParentIssueNumber = parentNumber;
_state.State.CommentId = devIssue.CommentId;
await _state.WriteStateAsync();

View File

@@ -11,7 +11,6 @@ public class Hubber : Grain, IGrainWithStringKey
{
private readonly IManageGithub _ghService;
public Hubber( IManageGithub ghService)
{
_ghService = ghService;
@@ -43,8 +42,31 @@ public class Hubber : Grain, IGrainWithStringKey
break;
}
}
public async Task ScheduleCommitSandboxRun(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest)
// GithubAgent
// -> create issue
// -> comment to issue
// -> create branch
// -> create PR
// -> commit to branch
public async Task CreateIssue()
{
// await _ghService.CreateIssue();
}
public async Task PostComment(string org, string repo,long issueNumber, string comment )
{
await _ghService.PostComment(org, repo, issueNumber, comment);
}
public async Task CreateBranch()
{
// await _ghService.CreateBranch();
}
public async Task CreatePullRequest()
{
// await _ghService.CreatePR();
}
public async Task CommitToBranch()
{
// await _ghService.CommitToBranch()
}
}

View File

@@ -59,15 +59,9 @@ public class ProductManager : SemanticPersona
public async Task CreateIssue(string org, string repo, long parentNumber, string input)
{
//TODO: Create branch and PR
var pmIssue = await _ghService.CreateIssue(new CreateIssueRequest
{
Label = $"{nameof(PM)}.{nameof(PM.Readme)}",
Org = org,
Repo = repo,
Input = input,
ParentNumber = parentNumber
});
var function = $"{nameof(PM)}.{nameof(PM.Readme)}";
var pmIssue = await _ghService.CreateIssue(org, repo, input, function, parentNumber);
_state.State.ParentIssueNumber = parentNumber;
_state.State.CommentId = pmIssue.CommentId;
await _state.WriteStateAsync();

View File

@@ -2,5 +2,5 @@ namespace Microsoft.AI.DevTeam;
public interface IManageSandbox : IGrainWithIntegerCompoundKey
{
Task ScheduleCommitSandboxRun(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest);
Task ScheduleCommitSandboxRun(string org, string repo, long parentIssueNumber, long issueNumber);
}

View File

@@ -20,9 +20,9 @@ public class Sandbox : Grain, IManageSandbox, IRemindable
_azService = azService;
_state = state;
}
public async Task ScheduleCommitSandboxRun(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest)
public async Task ScheduleCommitSandboxRun(string org, string repo, long parentIssueNumber, long issueNumber)
{
await StoreState(commitRequest, markTaskCompleteRequest, sandboxRequest);
await StoreState(org, repo, parentIssueNumber, issueNumber);
_reminder = await _reminderRegistry.RegisterOrUpdateReminder(
callingGrainId: this.GetGrainId(),
reminderName: ReminderName,
@@ -34,12 +34,12 @@ public class Sandbox : Grain, IManageSandbox, IRemindable
{
if (!_state.State.IsCompleted)
{
var sandboxId = $"sk-sandbox-{_state.State.SandboxRequest.Org}-{_state.State.SandboxRequest.Repo}-{_state.State.SandboxRequest.ParentIssueNumber}-{_state.State.SandboxRequest.IssueNumber}";
var sandboxId = $"sk-sandbox-{_state.State.Org}-{_state.State.Repo}-{_state.State.ParentIssueNumber}-{_state.State.IssueNumber}";
if (await _azService.IsSandboxCompleted(sandboxId))
{
await _azService.DeleteSandbox(sandboxId);
await _ghService.CommitToBranch(_state.State.CommitRequest);
await _ghService.MarkTaskComplete(_state.State.MarkTaskCompleteRequest);
await _ghService.CommitToBranch(_state.State.Org, _state.State.Repo, _state.State.ParentIssueNumber, _state.State.IssueNumber, _state.State.RootDir, _state.State.Branch);
await _ghService.MarkTaskComplete(_state.State.Org, _state.State.Repo, _state.State.CommentId);
await Cleanup();
}
}
@@ -49,11 +49,12 @@ public class Sandbox : Grain, IManageSandbox, IRemindable
}
}
private async Task StoreState(CommitRequest commitRequest, MarkTaskCompleteRequest markTaskCompleteRequest, SandboxRequest sandboxRequest)
private async Task StoreState(string org, string repo, long parentIssueNumber, long issueNumber)
{
_state.State.CommitRequest = commitRequest;
_state.State.MarkTaskCompleteRequest = markTaskCompleteRequest;
_state.State.SandboxRequest = sandboxRequest;
_state.State.Org = org;
_state.State.Repo = repo;
_state.State.ParentIssueNumber = parentIssueNumber;
// TODO: Add all of the state properties
_state.State.IsCompleted = false;
await _state.WriteStateAsync();
}
@@ -70,8 +71,13 @@ public class Sandbox : Grain, IManageSandbox, IRemindable
public class SandboxMetadata
{
public CommitRequest CommitRequest { get; set; }
public MarkTaskCompleteRequest MarkTaskCompleteRequest { get; set; }
public SandboxRequest SandboxRequest { get; set; }
public string Org { get; set; }
public string Repo { get; set; }
public long ParentIssueNumber { get; set; }
public long IssueNumber { get; set; }
public string RootDir { get; set; }
public string Branch { get; set; }
public int CommentId { get; set; }
public bool IsCompleted { get; set; }
}

View File

@@ -63,7 +63,7 @@ public class AzureService : IManageAzure
}
}
public async Task RunInSandbox(SandboxRequest request)
public async Task RunInSandbox(string org, string repo, long parentIssueNumber, long issueNumber)
{
try
{
@@ -71,10 +71,10 @@ public class AzureService : IManageAzure
new ArmClient(new AzureCliCredential())
: new ArmClient(new ManagedIdentityCredential(_azSettings.ManagedIdentity));
var runId = $"sk-sandbox-{request.Org}-{request.Repo}-{request.ParentIssueNumber}-{request.IssueNumber}";
var runId = $"sk-sandbox-{org}-{repo}-{parentIssueNumber}-{issueNumber}";
var resourceGroupResourceId = ResourceGroupResource.CreateResourceIdentifier(_azSettings.SubscriptionId, _azSettings.ContainerInstancesResourceGroup);
var resourceGroupResource = client.GetResourceGroupResource(resourceGroupResourceId);
var scriptPath = $"/azfiles/output/{request.Org}-{request.Repo}/{request.ParentIssueNumber}/{request.IssueNumber}/run.sh";
var scriptPath = $"/azfiles/output/{org}-{repo}/{parentIssueNumber}/{issueNumber}/run.sh";
var collection = resourceGroupResource.GetContainerGroups();
var data = new ContainerGroupData(new AzureLocation(_azSettings.Location), new ContainerInstanceContainer[]
{
@@ -113,33 +113,33 @@ public class AzureService : IManageAzure
}
public async Task Store(SaveOutputRequest request)
public async Task Store(string org, string repo, long parentIssueNumber, long issueNumber, string filename, string extension, string dir, string output)
{
try
{
var connectionString = $"DefaultEndpointsProtocol=https;AccountName={_azSettings.FilesAccountName};AccountKey={_azSettings.FilesAccountKey};EndpointSuffix=core.windows.net";
var parentDirName = $"{request.Directory}/{request.Org}-{request.Repo}";
var parentDirName = $"{dir}/{org}-{repo}";
var fileName = $"{request.FileName}.{request.Extension}";
var fileName = $"{filename}.{extension}";
var share = new ShareClient(connectionString, _azSettings.FilesShareName);
await share.CreateIfNotExistsAsync();
await share.GetDirectoryClient($"{request.Directory}").CreateIfNotExistsAsync(); ;
await share.GetDirectoryClient($"{dir}").CreateIfNotExistsAsync(); ;
var parentDir = share.GetDirectoryClient(parentDirName);
await parentDir.CreateIfNotExistsAsync();
var parentIssueDir = parentDir.GetSubdirectoryClient($"{request.ParentIssueNumber}");
var parentIssueDir = parentDir.GetSubdirectoryClient($"{parentIssueNumber}");
await parentIssueDir.CreateIfNotExistsAsync();
var directory = parentIssueDir.GetSubdirectoryClient($"{request.IssueNumber}");
var directory = parentIssueDir.GetSubdirectoryClient($"{issueNumber}");
await directory.CreateIfNotExistsAsync();
var file = directory.GetFileClient(fileName);
// hack to enable script to save files in the same directory
var cwdHack = "#!/bin/bash\n cd $(dirname $0)";
var output = request.Extension == "sh" ? request.Output.Replace("#!/bin/bash", cwdHack) : request.Output;
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(output)))
var contents = extension == "sh" ? output.Replace("#!/bin/bash", cwdHack) : output;
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
{
await file.CreateAsync(stream.Length);
await file.UploadRangeAsync(
@@ -151,39 +151,13 @@ public class AzureService : IManageAzure
{
_logger.LogError(ex, "Error storing output");
}
}
}
public interface IManageAzure
{
Task Store(SaveOutputRequest request);
Task RunInSandbox(SandboxRequest request);
Task Store(string org, string repo, long parentIssueNumber, long issueNumber, string filename, string extension, string dir, string output);
Task RunInSandbox(string org, string repo, long parentIssueNumber, long issueNumber);
Task<bool> IsSandboxCompleted(string sandboxId);
Task DeleteSandbox(string sandboxId);
}
public class SaveOutputRequest
{
public int ParentIssueNumber { get; set; }
public int IssueNumber { get; set; }
public string Output { get; set; }
public string Extension { get; set; }
public string Directory { get; set; }
public string FileName { get; set; }
public string Org { get; set; }
public string Repo { get; set; }
}
[GenerateSerializer]
public class SandboxRequest
{
[Id(0)]
public string Org { get; set; }
[Id(1)]
public string Repo { get; set; }
[Id(2)]
public int IssueNumber { get; set; }
[Id(3)]
public int ParentIssueNumber { get; set; }
}

View File

@@ -23,13 +23,13 @@ public class GithubService : IManageGithub
_httpClient = httpClient;
}
public async Task CommitToBranch(CommitRequest request)
public async Task CommitToBranch(string org, string repo, long parentNumber, long issueNumber, string rootDir, string branch)
{
try
{
var connectionString = $"DefaultEndpointsProtocol=https;AccountName={_azSettings.FilesAccountName};AccountKey={_azSettings.FilesAccountKey};EndpointSuffix=core.windows.net";
var dirName = $"{request.Dir}/{request.Org}-{request.Repo}/{request.ParentNumber}/{request.Number}";
var dirName = $"{rootDir}/{org}-{repo}/{parentNumber}/{issueNumber}";
var share = new ShareClient(connectionString, _azSettings.FilesShareName);
var directory = share.GetDirectoryClient(dirName);
@@ -53,8 +53,8 @@ public class GithubService : IManageGithub
var value = reader.ReadToEnd();
await _ghClient.Repository.Content.CreateFile(
request.Org, request.Repo, filePath,
new CreateFileRequest($"Commit message", value, request.Branch)); // TODO: add more meaningfull commit message
org, repo, filePath,
new CreateFileRequest($"Commit message", value, branch)); // TODO: add more meaningfull commit message
}
}
catch (Exception ex)
@@ -75,12 +75,12 @@ public class GithubService : IManageGithub
}
}
public async Task CreateBranch(CreateBranchRequest request)
public async Task CreateBranch(string org, string repo, string branch)
{
try
{
var ghRepo = await _ghClient.Repository.Get(request.Org, request.Repo);
await _ghClient.Git.Reference.CreateBranch(request.Org, request.Repo, request.Branch, ghRepo.DefaultBranch);
var ghRepo = await _ghClient.Repository.Get(org, repo);
await _ghClient.Git.Reference.CreateBranch(org, repo, branch, ghRepo.DefaultBranch);
}
catch (Exception ex)
{
@@ -103,19 +103,19 @@ public class GithubService : IManageGithub
}
}
public async Task<NewIssueResponse> CreateIssue(CreateIssueRequest request)
public async Task<NewIssueResponse> CreateIssue(string org, string repo, string input, string function, long parentNumber)
{
try
{
var newIssue = new NewIssue($"{request.Label} chain for #{request.ParentNumber}")
var newIssue = new NewIssue($"{function} chain for #{parentNumber}")
{
Body = request.Input,
Body = input,
};
newIssue.Labels.Add(request.Label);
newIssue.Labels.Add($"Parent.{request.ParentNumber}");
var issue = await _ghClient.Issue.Create(request.Org, request.Repo, newIssue);
var commentBody = $" - [ ] #{issue.Number} - tracks {request.Label}";
var comment = await _ghClient.Issue.Comment.Create(request.Org, request.Repo, (int)request.ParentNumber, commentBody);
newIssue.Labels.Add(function);
newIssue.Labels.Add($"Parent.{parentNumber}");
var issue = await _ghClient.Issue.Create(org, repo, newIssue);
var commentBody = $" - [ ] #{issue.Number} - tracks {function}";
var comment = await _ghClient.Issue.Comment.Create(org, repo, (int)parentNumber, commentBody);
return new NewIssueResponse
{
IssueNumber = issue.Number,
@@ -129,33 +129,31 @@ public class GithubService : IManageGithub
}
}
public async Task CreatePR(CreatePRRequest request)
public async Task CreatePR(string org, string repo, long number, string branch)
{
try
{
var ghRepo = await _ghClient.Repository.Get(request.Org, request.Repo);
await _ghClient.PullRequest.Create(request.Org, request.Repo, new NewPullRequest($"New app #{request.Number}", request.Branch, ghRepo.DefaultBranch));
var ghRepo = await _ghClient.Repository.Get(org, repo);
await _ghClient.PullRequest.Create(org, repo, new NewPullRequest($"New app #{number}", branch, ghRepo.DefaultBranch));
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating PR");
}
}
public async Task MarkTaskComplete(MarkTaskCompleteRequest request)
public async Task MarkTaskComplete(string org, string repo, int commentId)
{
try
{
var comment = await _ghClient.Issue.Comment.Get(request.Org, request.Repo, request.CommentId);
var comment = await _ghClient.Issue.Comment.Get(org, repo, commentId);
var updatedComment = comment.Body.Replace("[ ]", "[x]");
await _ghClient.Issue.Comment.Update(request.Org, request.Repo, request.CommentId, updatedComment);
await _ghClient.Issue.Comment.Update(org, repo, commentId, updatedComment);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error marking task complete");
}
}
public async Task PostComment(string org, string repo, long issueNumber, string comment)
@@ -224,66 +222,18 @@ public class FileResponse
public interface IManageGithub
{
Task<NewIssueResponse> CreateIssue(CreateIssueRequest request);
Task MarkTaskComplete(MarkTaskCompleteRequest request);
Task<NewIssueResponse> CreateIssue(string org, string repo, string input, string function, long parentNumber);
Task MarkTaskComplete(string org, string repo, int commentId);
Task CreatePR(CreatePRRequest request);
Task CreateBranch(CreateBranchRequest request);
Task CommitToBranch(CommitRequest request);
Task CreatePR(string org, string repo, long number, string branch);
Task CreateBranch(string org, string repo, string branch);
Task CommitToBranch(string org, string repo, long parentNumber, long issueNumber, string rootDir, string branch);
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);
}
[GenerateSerializer]
public class MarkTaskCompleteRequest
{
[Id(0)]
public string Org { get; set; }
[Id(1)]
public string Repo { get; set; }
[Id(2)]
public int CommentId { get; set; }
}
[GenerateSerializer]
public class CreateIssueRequest
{
[Id(0)]
public string Input { get; set; }
[Id(1)]
public string Label { get; set; }
[Id(2)]
public long ParentNumber { get; set; }
[Id(3)]
public string Org { get; set; }
[Id(4)]
public string Repo { get; set; }
}
public class CreateBranchRequest
{
public string Org { get; set; }
public string Repo { get; set; }
public string Branch { get; set; }
}
public class CreatePRRequest
{
public string Org { get; set; }
public string Repo { get; set; }
public string Branch { get; set; }
public int Number { get; set; }
}
public class PostCommentRequest
{
public string Org { get; set; }
public string Repo { get; set; }
public string Content { get; set; }
public int Number { get; set; }
}
[GenerateSerializer]
public class NewIssueResponse
{
@@ -292,20 +242,3 @@ public class NewIssueResponse
[Id(1)]
public int CommentId { get; set; }
}
[GenerateSerializer]
public class CommitRequest
{
[Id(0)]
public string Dir { get; set; }
[Id(1)]
public string Org { get; set; }
[Id(2)]
public string Repo { get; set; }
[Id(3)]
public int ParentNumber { get; set; }
[Id(4)]
public int Number { get; set; }
[Id(5)]
public string Branch { get; set; }
}