Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ChatRoom.Github #30

Merged
merged 2 commits into from
Jun 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 32 additions & 2 deletions ChatRoom.sln
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatRoom.Client.Tests", "te
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatRoom.OpenAI.Tests", "test\ChatRoom.OpenAI.Tests\ChatRoom.OpenAI.Tests.csproj", "{57D8D4B6-619F-4CAA-A118-DF89AB68DE1E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatRoom.BingSearch.Tests", "test\ChatRoom.BingSearch.Tests\ChatRoom.BingSearch.Tests.csproj", "{53726B9D-AF2F-4E3B-B33F-7FA362C6E47F}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatRoom.BingSearch.Tests", "test\ChatRoom.BingSearch.Tests\ChatRoom.BingSearch.Tests.csproj", "{53726B9D-AF2F-4E3B-B33F-7FA362C6E47F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatRoom.Powershell.Tests", "test\ChatRoom.Powershell.Tests\ChatRoom.Powershell.Tests.csproj", "{EE69B6B8-332F-48E6-AF7D-433489949ECD}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChatRoom.Powershell.Tests", "test\ChatRoom.Powershell.Tests\ChatRoom.Powershell.Tests.csproj", "{EE69B6B8-332F-48E6-AF7D-433489949ECD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatRoom.Github", "ChatRoom\ChatRoom.Github\ChatRoom.Github.csproj", "{DA54F7BA-1CA9-454A-B337-F231A68AB041}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChatRoom.Github.Tests", "test\ChatRoom.Github.Tests\ChatRoom.Github.Tests.csproj", "{0949EE2B-65CF-47C1-9A8C-80BD29B50588}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -176,6 +180,30 @@ Global
{EE69B6B8-332F-48E6-AF7D-433489949ECD}.Release|x64.Build.0 = Release|Any CPU
{EE69B6B8-332F-48E6-AF7D-433489949ECD}.Release|x86.ActiveCfg = Release|Any CPU
{EE69B6B8-332F-48E6-AF7D-433489949ECD}.Release|x86.Build.0 = Release|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Debug|x64.ActiveCfg = Debug|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Debug|x64.Build.0 = Debug|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Debug|x86.ActiveCfg = Debug|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Debug|x86.Build.0 = Debug|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Release|Any CPU.Build.0 = Release|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Release|x64.ActiveCfg = Release|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Release|x64.Build.0 = Release|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Release|x86.ActiveCfg = Release|Any CPU
{DA54F7BA-1CA9-454A-B337-F231A68AB041}.Release|x86.Build.0 = Release|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Debug|x64.ActiveCfg = Debug|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Debug|x64.Build.0 = Debug|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Debug|x86.ActiveCfg = Debug|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Debug|x86.Build.0 = Debug|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Release|Any CPU.Build.0 = Release|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Release|x64.ActiveCfg = Release|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Release|x64.Build.0 = Release|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Release|x86.ActiveCfg = Release|Any CPU
{0949EE2B-65CF-47C1-9A8C-80BD29B50588}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -192,6 +220,8 @@ Global
{57D8D4B6-619F-4CAA-A118-DF89AB68DE1E} = {4503B3D3-D2C7-4FE8-A450-5A051089635C}
{53726B9D-AF2F-4E3B-B33F-7FA362C6E47F} = {4503B3D3-D2C7-4FE8-A450-5A051089635C}
{EE69B6B8-332F-48E6-AF7D-433489949ECD} = {4503B3D3-D2C7-4FE8-A450-5A051089635C}
{DA54F7BA-1CA9-454A-B337-F231A68AB041} = {C0FE0076-894A-4462-8B31-3099EDBCE0A7}
{0949EE2B-65CF-47C1-9A8C-80BD29B50588} = {4503B3D3-D2C7-4FE8-A450-5A051089635C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E2F0A4B1-A064-41DD-B0C3-A4FF892EF46A}
Expand Down
2 changes: 1 addition & 1 deletion ChatRoom/ChatRoom.BingSearch/AgentFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public static IAgent CreateBingSearchAgent(BingSearchConfiguration config)
try
{
var reply = await innerAgent.GenerateReplyAsync(msgs, option, ct);
if (reply is AggregateMessage<ToolCallMessage, ToolCallResultMessage>)
if (reply is ToolCallAggregateMessage)
{
return await innerAgent.GenerateReplyAsync(msgs.Append(reply), option, ct);
}
Expand Down
1 change: 0 additions & 1 deletion ChatRoom/ChatRoom.BingSearch/BingSearchConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ public class BingSearchConfiguration
[Description("Azure OpenAI deployment name, will use $env:AZURE_OPENAI_DEPLOY_NAME if not provided")]
public string? AzureDeploymentName { get; set; } = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOY_NAME");


[JsonPropertyName("openai_api_key")]
[Description("OpenAI API key, will use $env:OPENAI_API_KEY if not provided")]
public string? OpenAiApiKey { get; set; } = Environment.GetEnvironmentVariable("OPENAI_API_KEY");
Expand Down
17 changes: 17 additions & 0 deletions ChatRoom/ChatRoom.Common/HostBuilderExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,23 @@ public static IHostBuilder AddAgentAsync<TAgent>(
});
}

public static IHostBuilder AddAgentAsync<TAgent>(
this IHostBuilder hostBuilder,
TAgent agent,
string selfDescription)
where TAgent : IAgent
{
return hostBuilder
.ConfigureServices(async (ctx, serviceCollections) =>
{
serviceCollections.AddSingleton(sp =>
{
var agentInfo = new AgentInfo(agent.Name, selfDescription);
return new AgentInfoAgent(agent, agentInfo);
});
});
}

public static async Task WaitForAgentsJoinRoomAsync(this IHost host)
{
var collections = host.Services.GetServices<AgentInfoAgent>();
Expand Down
31 changes: 31 additions & 0 deletions ChatRoom/ChatRoom.Github/AgentFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using AutoGen.OpenAI;
using AutoGen.OpenAI.Extension;
using Azure.AI.OpenAI;
using Octokit;

namespace ChatRoom.Github;

internal static class AgentFactory
{
public static IssueHelper CreateIssueHelperAgent(
OpenAIClient openaiClient,
string deployModelName,
GitHubClient gitHubClient,
string name = "issue-helper",
string systemMessage = "You are a github issue helper")
{
var openaiChatAgent = new OpenAIChatAgent(
openAIClient: openaiClient,
name: name,
modelName: deployModelName!,
systemMessage: systemMessage)
.RegisterMessageConnector();

return new IssueHelper(openaiChatAgent, gitHubClient);
}
}
31 changes: 31 additions & 0 deletions ChatRoom/ChatRoom.Github/ChatRoom.Github.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<ToolCommandName>chatroom-github</ToolCommandName>
<PackAsTool>true</PackAsTool>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

<Import Project="$(RepoRoot)/nuget/nuget-package.props" />

<ItemGroup>
<InternalsVisibleTo Include="ChatRoom.Github.Tests" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Spectre.Console.Cli" />
<PackageReference Include="AutoGen" />
<PackageReference Include="AutoGen.SourceGenerator" />
<PackageReference Include="Octokit" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\ChatRoom.Common\ChatRoom.SDK.csproj" />
</ItemGroup>

</Project>
86 changes: 86 additions & 0 deletions ChatRoom/ChatRoom.Github/GithubCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using AutoGen.Core;
using Azure.AI.OpenAI;
using ChatRoom.SDK;
using Microsoft.Extensions.Hosting;
using Microsoft.SemanticKernel.Agents;
using Octokit;
using Spectre.Console.Cli;

namespace ChatRoom.Github;

internal class GithubCommand : AsyncCommand<ChatRoomAgentClientCommandSettings>
{
public static string Description { get; } = """
Github agents for ChatRoom

The following agents are available:
- issue-helper: A github issue helper agent
""";

public override async Task<int> ExecuteAsync(CommandContext context, ChatRoomAgentClientCommandSettings settings)
{
var config = settings.ConfigFile is not null
? JsonSerializer.Deserialize<GithubConfiguration>(File.ReadAllText(settings.ConfigFile))!
: new GithubConfiguration();

OpenAIClient? openaiClient = null;
string? deployModelName = null;
IAgent? issueHelper = null;
if (config.LLMType == LLMType.AOAI)
{
if (config.AzureOpenAiKey is string
&& config.AzureOpenAiEndpoint is string
&& config.AzureDeploymentName is string)
{
openaiClient = new OpenAIClient(new Uri(config.AzureOpenAiEndpoint), new Azure.AzureKeyCredential(config.AzureOpenAiKey));
deployModelName = config.AzureDeploymentName;
}
else
{
var defaultReply = "Azure OpenAI endpoint, key, or deployment name not found. Please provide Azure OpenAI endpoint, key, and deployment name in the configuration file or via env:AZURE_OPENAI_ENDPOINT, env:AZURE_OPENAI_API_KEY, env:AZURE_OPENAI_DEPLOY_NAME";
issueHelper = new DefaultReplyAgent(config.IssueHelper.Name, defaultReply);
}
}
else
{
if (config.OpenAiApiKey is string && config.OpenAiModelId is string)
{
openaiClient = new OpenAIClient(config.OpenAiApiKey);
deployModelName = config.OpenAiModelId;
}
else
{
var defaultReply = "OpenAI API key or model id not found. Please provide OpenAI API key and model id in the configuration file or via env:OPENAI_API_KEY, env:OPENAI_MODEL_ID";
issueHelper = new DefaultReplyAgent(config.IssueHelper.Name, defaultReply);
}
}

var ghClient = new GitHubClient(new ProductHeaderValue("ChatRoom"));
if (config.GithubToken is string)
{
ghClient.Credentials = new Credentials(config.GithubToken);
}

if (issueHelper is null)
{
issueHelper = AgentFactory.CreateIssueHelperAgent(openaiClient!, deployModelName!, ghClient, config.IssueHelper.Name, config.IssueHelper.SystemMessage);
};

var host = Host.CreateDefaultBuilder()
.AddAgentAsync(issueHelper, config.IssueHelper.Description)
.UseChatRoom(roomName: settings.Room ?? "room", port: settings.Port ?? 30000)
.Build();

await host.StartAsync();
await host.WaitForAgentsJoinRoomAsync();
await host.WaitForShutdownAsync();

return 0;
}
}
67 changes: 67 additions & 0 deletions ChatRoom/ChatRoom.Github/GithubConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Json.Schema.Generation;

namespace ChatRoom.Github;

public enum LLMType
{
[Description("Azure OpenAI")]
AOAI = 0, // Azure OpenAI

[Description("OpenAI")]
OpenAI = 1 // OpenAI
}

public class IssueHelperConfiguration
{
[Description("Name of the issue helper agent, default is 'issue-helper'")]
[JsonPropertyName("name")]
public string Name { get; set; } = "issue-helper";

[Description("System message, default is 'You are a github issue helper'")]
[JsonPropertyName("system_message")]
public string SystemMessage { get; set; } = "You are a github issue helper";

[Description("Agent description, default is 'I am a github issue helper, I can help you with your github issues.'")]
[JsonPropertyName("description")]
public string Description { get; set; } = "I am a github issue helper, I can help you with your github issues.";
}

public class GithubConfiguration
{
[Description("Issue helper configuration")]
public IssueHelperConfiguration IssueHelper { get; set; } = new IssueHelperConfiguration();

[JsonPropertyName("github_token")]
[Description("GitHub token, will use $env:GITHUB_TOKEN if not provided")]
public string? GithubToken { get; set; } = Environment.GetEnvironmentVariable("GITHUB_TOKEN");

[Description("Language model type, will use Azure OpenAI if not provided")]
[JsonPropertyName("llm_type")]
public LLMType LLMType { get; set; } = LLMType.AOAI;

[JsonPropertyName("azure_openai_endpoint")]
[Description("Azure OpenAI endpoint, will use $env:AZURE_OPENAI_ENDPOINT if not provided")]
public string? AzureOpenAiEndpoint { get; set; } = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");

[JsonPropertyName("azure_openai_key")]
[Description("Azure OpenAI key, will use $env:AZURE_OPENAI_API_KEY if not provided")]
public string? AzureOpenAiKey { get; set; } = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");

[JsonPropertyName("azure_deployment_name")]
[Description("Azure OpenAI deployment name, will use $env:AZURE_OPENAI_DEPLOY_NAME if not provided")]
public string? AzureDeploymentName { get; set; } = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOY_NAME");

[JsonPropertyName("openai_api_key")]
[Description("OpenAI API key, will use $env:OPENAI_API_KEY if not provided")]
public string? OpenAiApiKey { get; set; } = Environment.GetEnvironmentVariable("OPENAI_API_KEY");

[JsonPropertyName("openai_model_id")]
[Description("OpenAI model ID, will use gpt-3.5-turbo if not provided")]
public string OpenAiModelId { get; set; } = "gpt-3.5-turbo";
}
Loading