mirror of
https://github.com/microsoft/autogen.git
synced 2026-02-16 01:05:28 -05:00
* docs update WIP * getting started guide updated * update getting started guide * clarify github app creation * add webhook secret to getting started guide and gh-flow app * restructure Readme * fix the Organization assumption * add mermaid diagram of the event flow * devtunnel feature to devcontainer * throw all the exceptions and add the history to the prompt * Update github-flow.md * update readme
162 lines
6.8 KiB
C#
162 lines
6.8 KiB
C#
using Microsoft.AI.DevTeam;
|
|
using Microsoft.AI.DevTeam.Skills;
|
|
using Octokit.Webhooks;
|
|
using Octokit.Webhooks.Events;
|
|
using Octokit.Webhooks.Events.IssueComment;
|
|
using Octokit.Webhooks.Events.Issues;
|
|
using Octokit.Webhooks.Models;
|
|
using Orleans.Runtime;
|
|
|
|
public sealed class GithubWebHookProcessor : WebhookEventProcessor
|
|
{
|
|
private readonly ILogger<GithubWebHookProcessor> _logger;
|
|
private readonly IClusterClient _client;
|
|
private readonly IManageGithub _ghService;
|
|
private readonly IManageAzure _azService;
|
|
|
|
public GithubWebHookProcessor(ILogger<GithubWebHookProcessor> logger,
|
|
IClusterClient client, IManageGithub ghService, IManageAzure azService)
|
|
{
|
|
_logger = logger;
|
|
_client = client;
|
|
_ghService = ghService;
|
|
_azService = azService;
|
|
}
|
|
protected override async Task ProcessIssuesWebhookAsync(WebhookHeaders headers, IssuesEvent issuesEvent, IssuesAction action)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation("Processing issue event");
|
|
var org = issuesEvent.Repository.Owner.Login;
|
|
var repo = issuesEvent.Repository.Name;
|
|
var issueNumber = issuesEvent.Issue.Number;
|
|
var input = issuesEvent.Issue.Body;
|
|
// Assumes the label follows the following convention: Skill.Function example: PM.Readme
|
|
// Also, we've introduced the Parent label, that ties the sub-issue with the parent issue
|
|
var labels = issuesEvent.Issue.Labels
|
|
.Select(l => l.Name.Split('.'))
|
|
.Where(parts => parts.Length == 2)
|
|
.ToDictionary(parts => parts[0], parts => parts[1]);
|
|
var skillName = labels.Keys.Where(k=>k != "Parent").FirstOrDefault();
|
|
long? parentNumber = labels.ContainsKey("Parent") ? long.Parse(labels["Parent"]) : null;
|
|
|
|
var suffix = $"{org}-{repo}";
|
|
if (issuesEvent.Action == IssuesAction.Opened)
|
|
{
|
|
_logger.LogInformation("Processing HandleNewAsk");
|
|
await HandleNewAsk(issueNumber,parentNumber, skillName, labels[skillName], suffix, input, org, repo);
|
|
}
|
|
else if (issuesEvent.Action == IssuesAction.Closed && issuesEvent.Issue.User.Type.Value == UserType.Bot)
|
|
{
|
|
_logger.LogInformation("Processing HandleClosingIssue");
|
|
await HandleClosingIssue(issueNumber, parentNumber,skillName, labels[skillName], suffix, org, repo);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Processing issue event");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
protected override async Task ProcessIssueCommentWebhookAsync(
|
|
WebhookHeaders headers,
|
|
IssueCommentEvent issueCommentEvent,
|
|
IssueCommentAction action)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation("Processing issue comment event");
|
|
var org = issueCommentEvent.Repository.Owner.Login;
|
|
var repo = issueCommentEvent.Repository.Name;
|
|
var issueNumber = issueCommentEvent.Issue.Number;
|
|
var input = issueCommentEvent.Comment.Body;
|
|
// Assumes the label follows the following convention: Skill.Function example: PM.Readme
|
|
var labels = issueCommentEvent.Issue.Labels
|
|
.Select(l => l.Name.Split('.'))
|
|
.Where(parts => parts.Length == 2)
|
|
.ToDictionary(parts => parts[0], parts => parts[1]);
|
|
var skillName = labels.Keys.Where(k=>k != "Parent").FirstOrDefault();
|
|
long? parentNumber = labels.ContainsKey("Parent") ? long.Parse(labels["Parent"]) : null;
|
|
var suffix = $"{org}-{repo}";
|
|
// we only respond to non-bot comments
|
|
if (issueCommentEvent.Sender.Type.Value != UserType.Bot)
|
|
{
|
|
await HandleNewAsk(issueNumber, parentNumber, skillName, labels[skillName], suffix, input, org, repo);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Processing issue comment event");
|
|
throw;
|
|
}
|
|
|
|
}
|
|
|
|
private async Task HandleClosingIssue(long issueNumber, long? parentNumber, string skillName, string functionName, string suffix, string org, string repo)
|
|
{
|
|
var streamProvider = _client.GetStreamProvider("StreamProvider");
|
|
var streamId = StreamId.Create(Consts.MainNamespace, suffix+issueNumber.ToString());
|
|
var stream = streamProvider.GetStream<Event>(streamId);
|
|
var eventType = (skillName, functionName) switch
|
|
{
|
|
(nameof(PM), nameof(PM.Readme)) => EventType.ReadmeChainClosed,
|
|
(nameof(DevLead), nameof(DevLead.Plan)) => EventType.DevPlanChainClosed,
|
|
(nameof(Developer), nameof(Developer.Implement)) => EventType.CodeChainClosed,
|
|
_ => EventType.NewAsk
|
|
};
|
|
var data = new Dictionary<string, string>
|
|
{
|
|
{ "org", org },
|
|
{ "repo", repo },
|
|
{ "issueNumber", issueNumber.ToString() },
|
|
{ "parentNumber", parentNumber?.ToString()}
|
|
};
|
|
|
|
await stream.OnNextAsync(new Event
|
|
{
|
|
Type = eventType,
|
|
Data = data
|
|
});
|
|
}
|
|
|
|
private async Task HandleNewAsk(long issueNumber, long? parentNumber, string skillName, string functionName, string suffix, string input, string org, string repo)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation("Handling new ask");
|
|
var streamProvider = _client.GetStreamProvider("StreamProvider");
|
|
var streamId = StreamId.Create(Consts.MainNamespace, suffix+issueNumber.ToString());
|
|
var stream = streamProvider.GetStream<Event>(streamId);
|
|
|
|
var eventType = (skillName, functionName) switch
|
|
{
|
|
("Do", "It") => EventType.NewAsk,
|
|
(nameof(PM), nameof(PM.Readme)) => EventType.ReadmeRequested,
|
|
(nameof(DevLead), nameof(DevLead.Plan)) => EventType.DevPlanRequested,
|
|
(nameof(Developer), nameof(Developer.Implement)) => EventType.CodeGenerationRequested,
|
|
_ => EventType.NewAsk
|
|
};
|
|
var data = new Dictionary<string, string>
|
|
{
|
|
{ "org", org },
|
|
{ "repo", repo },
|
|
{ "issueNumber", issueNumber.ToString() },
|
|
{ "parentNumber", parentNumber?.ToString()}
|
|
};
|
|
await stream.OnNextAsync(new Event
|
|
{
|
|
Type = eventType,
|
|
Message = input,
|
|
Data = data
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Handling new ask");
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|