mirror of
https://github.com/microsoft/autogen.git
synced 2025-07-08 09:31:51 +00:00

* update readme * update * update * update * update * update * update * add sample project * revert notebook change back * update * update interactive version * add nuget package * refactor Message * update example * add azure nightly build pipeline * Set up CI with Azure Pipelines [skip ci] * Update nightly-build.yml for Azure Pipelines * add dotnet interactive package * add dotnet interactive package * update pipeline * add nuget feed back * remove dotnet-tool feed * remove dotnet-tool feed comment * update pipeline * update build name * Update nightly-build.yml * Delete .github/workflows/dotnet-ci.yml * update * add working_dir to use step * add initateChat api * update oai package * Update dotnet-build.yml * Update dotnet-run-openai-test-and-notebooks.yml * update build workflow * update build workflow * update nuget feed * update nuget feed * update aoai and sk version * Update InteractiveService.cs * add support for GPT 4V * add DalleAndGPT4V example * update example * add user proxy agent * add readme * bump version * update example * add dotnet interactive hook * update * udpate tests * add website * update index.md * add docs * update doc * move sk dependency out of core package * udpate doc * Update Use-function-call.md * add type safe function call document * update doc * update doc * add dock * Update Use-function-call.md * add GenerateReplyOptions * remove IChatLLM * update version * update doc * update website * add sample * fix link * add middleware agent * clean up doc * bump version * update doc * update * add Other Language * remove warnings * add sign.props * add sign step * fix pipelien * auth * real sign * disable PR trigger * update * disable PR trigger * use microbuild machine * update build pipeline to add publish to internal feed * add internal feed * fix build pipeline * add dotnet prefix * update ci * add build number * update run number * update source * update token * update * remove adding source * add publish to github package * try again * try again * ask for write pacakge * disable package when branch is not main * update * implement streaming agent * add test for streaming function call * update * fix #1588 * enable PR check for dotnet branch * add website readme * only publish to dotnet feed when pushing to dotnet branch * remove openai-test-and-notebooks workflow * update readme * update readme * update workflow * update getting-start * upgrade test and sample proejct to use .net 8 * fix global.json format && make loadFromConfig API internal only before implementing * update * add support for LM studio * add doc * Update README.md * add push and workflow_dispatch trigger * disable PR for main * add dotnet env * Update Installation.md * add nuget * refer to newtonsoft 13 * update branch to dotnet in docfx * Update Installation.md * pull out HumanInputMiddleware and FunctionCallMiddleware * fix tests * add link to sample folder * refactor message * refactor over IMessage * add more tests * add more test * fix build error * rename header * add semantic kernel project * update sk example * update dotnet version * add LMStudio function call example * rename LLaMAFunctin * remove dotnet run openai test and notebook workflow * add FunctionContract and test * update doc * add documents * add workflow * update * update sample * fix warning in test * reult length can be less then maximumOutputToKeep (#1804) * merge with main * add option to retrieve inner agent and middlewares from MiddlewareAgent * update doc * adjust namespace * update readme * fix test * use IMessage * more updates * update * fix test * add comments * use FunctionContract to replace FunctionDefinition * move AutoGen contrac to AutoGen.Core * update installation * refactor streamingAgent by adding StreamingMessage type * update sample * update samples * update * update * add test * fix test * bump version * add openaichat test * update * Update Example03_Agent_FunctionCall.cs * [.Net] improve docs (#1862) * add doc * add doc * add doc * add doc * add doc * add doc * update * fix test error * fix some error * fix test * fix test * add more tests * edits --------- Co-authored-by: ekzhu <ekzhu@users.noreply.github.com> * [.Net] Add fill form example (#1911) * add form filler example * update * fix ci error * [.Net] Add using AutoGen.Core in source generator (#1983) * fix using namespace bug in source generator * remove using in sourcegenerator test * disable PR test * Add .idea to .gitignore (#1988) * [.Net] publish to nuget.org feed (#1987) * publish to nuget * update ci * update dotnet-release * update release pipeline * add source * remove empty symbol package * update pipeline * remove tag * update installation guide * [.Net] Rename some classes && APIs based on doc review (#1980) * rename sequential group chat to round robin group chat * rename to sendInstruction * rename workflow to graph * rename some api * bump version * move Graph to GroupChat folder * rename fill application example * [.Net] Improve package description (#2161) * add discord link and update package description * Update getting-start.md * [.Net] Fix document comment from the most recent AutoGen.Net engineer sync (#2231) * update * rename RegisterPrintMessageHook to RegisterPrintMessage * update website * update update.md * fix link error * [.Net] Enable JsonMode and deterministic output in AutoGen.OpenAI OpenAIChatAgent (#2347) * update openai version && add sample for json output * add example in web * update update.md * update image url * [.Net] Add AutoGen.Mistral package (#2330) * add mstral client * enable streaming support * add mistralClientAgent * add test for function call * add extension * add support for toolcall and toolcall result message * add support for aggregate message * implement streaming function call * track (#2471) * [.Net] add mistral example (#2482) * update existing examples to use messageCOnnector * add overview * add function call document * add example 14 * add mistral token count usage example * update version * Update dotnet-release.yml (#2488) * update * revert gitattributes --------- Co-authored-by: mhensen <mh@webvize.nl> Co-authored-by: ekzhu <ekzhu@users.noreply.github.com> Co-authored-by: Krzysztof Kasprowicz <60486987+Krzysztof318@users.noreply.github.com>
378 lines
15 KiB
C#
378 lines
15 KiB
C#
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Example07_Dynamic_GroupChat_Calculate_Fibonacci.cs
|
|
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using AutoGen;
|
|
using AutoGen.BasicSample;
|
|
using AutoGen.DotnetInteractive;
|
|
using AutoGen.Core;
|
|
using AutoGen.OpenAI;
|
|
using FluentAssertions;
|
|
|
|
public partial class Example07_Dynamic_GroupChat_Calculate_Fibonacci
|
|
{
|
|
#region reviewer_function
|
|
public struct CodeReviewResult
|
|
{
|
|
public bool HasMultipleCodeBlocks { get; set; }
|
|
public bool IsTopLevelStatement { get; set; }
|
|
public bool IsDotnetCodeBlock { get; set; }
|
|
public bool IsPrintResultToConsole { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// review code block
|
|
/// </summary>
|
|
/// <param name="hasMultipleCodeBlocks">true if there're multipe csharp code blocks</param>
|
|
/// <param name="isTopLevelStatement">true if the code is in top level statement</param>
|
|
/// <param name="isDotnetCodeBlock">true if the code block is csharp code block</param>
|
|
/// <param name="isPrintResultToConsole">true if the code block print out result to console</param>
|
|
[Function]
|
|
public async Task<string> ReviewCodeBlock(
|
|
bool hasMultipleCodeBlocks,
|
|
bool isTopLevelStatement,
|
|
bool isDotnetCodeBlock,
|
|
bool isPrintResultToConsole)
|
|
{
|
|
var obj = new CodeReviewResult
|
|
{
|
|
HasMultipleCodeBlocks = hasMultipleCodeBlocks,
|
|
IsTopLevelStatement = isTopLevelStatement,
|
|
IsDotnetCodeBlock = isDotnetCodeBlock,
|
|
IsPrintResultToConsole = isPrintResultToConsole,
|
|
};
|
|
|
|
return JsonSerializer.Serialize(obj);
|
|
}
|
|
#endregion reviewer_function
|
|
|
|
#region create_coder
|
|
public static async Task<IAgent> CreateCoderAgentAsync()
|
|
{
|
|
var gpt3Config = LLMConfiguration.GetAzureOpenAIGPT3_5_Turbo();
|
|
var coder = new GPTAgent(
|
|
name: "coder",
|
|
systemMessage: @"You act as dotnet coder, you write dotnet code to resolve task. Once you finish writing code, ask runner to run the code for you.
|
|
|
|
Here're some rules to follow on writing dotnet code:
|
|
- put code between ```csharp and ```
|
|
- Avoid adding `using` keyword when creating disposable object. e.g `var httpClient = new HttpClient()`
|
|
- Try to use `var` instead of explicit type.
|
|
- Try avoid using external library, use .NET Core library instead.
|
|
- Use top level statement to write code.
|
|
- Always print out the result to console. Don't write code that doesn't print out anything.
|
|
|
|
If you need to install nuget packages, put nuget packages in the following format:
|
|
```nuget
|
|
nuget_package_name
|
|
```
|
|
|
|
If your code is incorrect, runner will tell you the error message. Fix the error and send the code again.",
|
|
config: gpt3Config,
|
|
temperature: 0.4f)
|
|
.RegisterPrintMessage();
|
|
|
|
return coder;
|
|
}
|
|
#endregion create_coder
|
|
|
|
#region create_runner
|
|
public static async Task<IAgent> CreateRunnerAgentAsync(InteractiveService service)
|
|
{
|
|
var runner = new AssistantAgent(
|
|
name: "runner",
|
|
systemMessage: "You run dotnet code",
|
|
defaultReply: "No code available.")
|
|
.RegisterDotnetCodeBlockExectionHook(interactiveService: service)
|
|
.RegisterReply(async (msgs, _) =>
|
|
{
|
|
if (msgs.Count() == 0)
|
|
{
|
|
return new TextMessage(Role.Assistant, "No code available. Coder please write code");
|
|
}
|
|
|
|
return null;
|
|
})
|
|
.RegisterPreProcess(async (msgs, _) =>
|
|
{
|
|
// retrieve the most recent message from coder
|
|
var coderMsg = msgs.LastOrDefault(msg => msg.From == "coder");
|
|
if (coderMsg is null)
|
|
{
|
|
return Enumerable.Empty<IMessage>();
|
|
}
|
|
else
|
|
{
|
|
return new[] { coderMsg };
|
|
}
|
|
})
|
|
.RegisterPrintMessage();
|
|
|
|
return runner;
|
|
}
|
|
#endregion create_runner
|
|
|
|
#region create_admin
|
|
public static async Task<IAgent> CreateAdminAsync()
|
|
{
|
|
var gpt3Config = LLMConfiguration.GetAzureOpenAIGPT3_5_Turbo();
|
|
var admin = new GPTAgent(
|
|
name: "admin",
|
|
systemMessage: "You are group admin, terminate the group chat once task is completed by saying [TERMINATE] plus the final answer",
|
|
temperature: 0,
|
|
config: gpt3Config)
|
|
.RegisterPostProcess(async (_, reply, _) =>
|
|
{
|
|
if (reply is TextMessage textMessage && textMessage.Content.Contains("TERMINATE") is true)
|
|
{
|
|
var content = $"{textMessage.Content}\n\n {GroupChatExtension.TERMINATE}";
|
|
|
|
return new TextMessage(Role.Assistant, content, from: reply.From);
|
|
}
|
|
|
|
return reply;
|
|
});
|
|
|
|
return admin;
|
|
}
|
|
#endregion create_admin
|
|
|
|
#region create_reviewer
|
|
public static async Task<IAgent> CreateReviewerAgentAsync()
|
|
{
|
|
var gpt3Config = LLMConfiguration.GetAzureOpenAIGPT3_5_Turbo();
|
|
var functions = new Example07_Dynamic_GroupChat_Calculate_Fibonacci();
|
|
var reviewer = new GPTAgent(
|
|
name: "code_reviewer",
|
|
systemMessage: @"You review code block from coder",
|
|
config: gpt3Config,
|
|
functions: [functions.ReviewCodeBlockFunction],
|
|
functionMap: new Dictionary<string, Func<string, Task<string>>>()
|
|
{
|
|
{ nameof(ReviewCodeBlock), functions.ReviewCodeBlockWrapper },
|
|
})
|
|
.RegisterMiddleware(async (msgs, option, innerAgent, ct) =>
|
|
{
|
|
var maxRetry = 3;
|
|
var reply = await innerAgent.GenerateReplyAsync(msgs, option, ct);
|
|
while (maxRetry-- > 0)
|
|
{
|
|
if (reply.GetToolCalls() is var toolCalls && toolCalls.Count() == 1 && toolCalls[0].FunctionName == nameof(ReviewCodeBlock))
|
|
{
|
|
var toolCallResult = reply.GetContent();
|
|
var reviewResultObj = JsonSerializer.Deserialize<CodeReviewResult>(toolCallResult);
|
|
var reviews = new List<string>();
|
|
if (reviewResultObj.HasMultipleCodeBlocks)
|
|
{
|
|
var fixCodeBlockPrompt = @"There're multiple code blocks, please combine them into one code block";
|
|
reviews.Add(fixCodeBlockPrompt);
|
|
}
|
|
|
|
if (reviewResultObj.IsDotnetCodeBlock is false)
|
|
{
|
|
var fixCodeBlockPrompt = @"The code block is not csharp code block, please write dotnet code only";
|
|
reviews.Add(fixCodeBlockPrompt);
|
|
}
|
|
|
|
if (reviewResultObj.IsTopLevelStatement is false)
|
|
{
|
|
var fixCodeBlockPrompt = @"The code is not top level statement, please rewrite your dotnet code using top level statement";
|
|
reviews.Add(fixCodeBlockPrompt);
|
|
}
|
|
|
|
if (reviewResultObj.IsPrintResultToConsole is false)
|
|
{
|
|
var fixCodeBlockPrompt = @"The code doesn't print out result to console, please print out result to console";
|
|
reviews.Add(fixCodeBlockPrompt);
|
|
}
|
|
|
|
if (reviews.Count > 0)
|
|
{
|
|
var sb = new StringBuilder();
|
|
sb.AppendLine("There're some comments from code reviewer, please fix these comments");
|
|
foreach (var review in reviews)
|
|
{
|
|
sb.AppendLine($"- {review}");
|
|
}
|
|
|
|
return new TextMessage(Role.Assistant, sb.ToString(), from: "code_reviewer");
|
|
}
|
|
else
|
|
{
|
|
var msg = new TextMessage(Role.Assistant, "The code looks good, please ask runner to run the code for you.")
|
|
{
|
|
From = "code_reviewer",
|
|
};
|
|
|
|
return msg;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
var originalContent = reply.GetContent();
|
|
var prompt = $@"Please convert the content to ReviewCodeBlock function arguments.
|
|
|
|
## Original Content
|
|
{originalContent}";
|
|
|
|
reply = await innerAgent.SendAsync(prompt, msgs, ct);
|
|
}
|
|
}
|
|
|
|
throw new Exception("Failed to review code block");
|
|
})
|
|
.RegisterPrintMessage();
|
|
|
|
return reviewer;
|
|
}
|
|
#endregion create_reviewer
|
|
|
|
public static async Task RunWorkflowAsync()
|
|
{
|
|
long the39thFibonacciNumber = 63245986;
|
|
var workDir = Path.Combine(Path.GetTempPath(), "InteractiveService");
|
|
if (!Directory.Exists(workDir))
|
|
Directory.CreateDirectory(workDir);
|
|
|
|
using var service = new InteractiveService(workDir);
|
|
var dotnetInteractiveFunctions = new DotnetInteractiveFunction(service);
|
|
|
|
await service.StartAsync(workDir, default);
|
|
|
|
#region create_workflow
|
|
var reviewer = await CreateReviewerAgentAsync();
|
|
var coder = await CreateCoderAgentAsync();
|
|
var runner = await CreateRunnerAgentAsync(service);
|
|
var admin = await CreateAdminAsync();
|
|
|
|
var admin2CoderTransition = Transition.Create(admin, coder);
|
|
var coder2ReviewerTransition = Transition.Create(coder, reviewer);
|
|
var reviewer2RunnerTransition = Transition.Create(
|
|
from: reviewer,
|
|
to: runner,
|
|
canTransitionAsync: async (from, to, messages) =>
|
|
{
|
|
var lastMessage = messages.Last();
|
|
if (lastMessage is TextMessage textMessage && textMessage.Content.ToLower().Contains("the code looks good, please ask runner to run the code for you.") is true)
|
|
{
|
|
// ask runner to run the code
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
var reviewer2CoderTransition = Transition.Create(
|
|
from: reviewer,
|
|
to: coder,
|
|
canTransitionAsync: async (from, to, messages) =>
|
|
{
|
|
var lastMessage = messages.Last();
|
|
if (lastMessage is TextMessage textMessage && textMessage.Content.ToLower().Contains("there're some comments from code reviewer, please fix these comments") is true)
|
|
{
|
|
// ask coder to fix the code based on reviewer's comments
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
|
|
var runner2CoderTransition = Transition.Create(
|
|
from: runner,
|
|
to: coder,
|
|
canTransitionAsync: async (from, to, messages) =>
|
|
{
|
|
var lastMessage = messages.Last();
|
|
if (lastMessage is TextMessage textMessage && textMessage.Content.ToLower().Contains("error") is true)
|
|
{
|
|
// ask coder to fix the error
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
});
|
|
var runner2AdminTransition = Transition.Create(runner, admin);
|
|
|
|
var workflow = new Graph(
|
|
[
|
|
admin2CoderTransition,
|
|
coder2ReviewerTransition,
|
|
reviewer2RunnerTransition,
|
|
reviewer2CoderTransition,
|
|
runner2CoderTransition,
|
|
runner2AdminTransition,
|
|
]);
|
|
#endregion create_workflow
|
|
|
|
#region create_group_chat_with_workflow
|
|
var groupChat = new GroupChat(
|
|
admin: admin,
|
|
workflow: workflow,
|
|
members:
|
|
[
|
|
admin,
|
|
coder,
|
|
runner,
|
|
reviewer,
|
|
]);
|
|
|
|
admin.SendIntroduction("Welcome to my group, work together to resolve my task", groupChat);
|
|
coder.SendIntroduction("I will write dotnet code to resolve task", groupChat);
|
|
reviewer.SendIntroduction("I will review dotnet code", groupChat);
|
|
runner.SendIntroduction("I will run dotnet code once the review is done", groupChat);
|
|
|
|
var groupChatManager = new GroupChatManager(groupChat);
|
|
var conversationHistory = await admin.InitiateChatAsync(groupChatManager, "What's the 39th of fibonacci number?", maxRound: 10);
|
|
#endregion create_group_chat_with_workflow
|
|
// the last message is from admin, which is the termination message
|
|
var lastMessage = conversationHistory.Last();
|
|
lastMessage.From.Should().Be("admin");
|
|
lastMessage.IsGroupChatTerminateMessage().Should().BeTrue();
|
|
lastMessage.Should().BeOfType<TextMessage>();
|
|
lastMessage.GetContent().Should().Contain(the39thFibonacciNumber.ToString());
|
|
}
|
|
|
|
public static async Task RunAsync()
|
|
{
|
|
long the39thFibonacciNumber = 63245986;
|
|
var workDir = Path.Combine(Path.GetTempPath(), "InteractiveService");
|
|
if (!Directory.Exists(workDir))
|
|
Directory.CreateDirectory(workDir);
|
|
|
|
using var service = new InteractiveService(workDir);
|
|
var dotnetInteractiveFunctions = new DotnetInteractiveFunction(service);
|
|
|
|
await service.StartAsync(workDir, default);
|
|
#region create_group_chat
|
|
var reviewer = await CreateReviewerAgentAsync();
|
|
var coder = await CreateCoderAgentAsync();
|
|
var runner = await CreateRunnerAgentAsync(service);
|
|
var admin = await CreateAdminAsync();
|
|
var groupChat = new GroupChat(
|
|
admin: admin,
|
|
members:
|
|
[
|
|
admin,
|
|
coder,
|
|
runner,
|
|
reviewer,
|
|
]);
|
|
|
|
admin.SendIntroduction("Welcome to my group, work together to resolve my task", groupChat);
|
|
coder.SendIntroduction("I will write dotnet code to resolve task", groupChat);
|
|
reviewer.SendIntroduction("I will review dotnet code", groupChat);
|
|
runner.SendIntroduction("I will run dotnet code once the review is done", groupChat);
|
|
|
|
var groupChatManager = new GroupChatManager(groupChat);
|
|
var conversationHistory = await admin.InitiateChatAsync(groupChatManager, "What's the 39th of fibonacci number?", maxRound: 10);
|
|
|
|
// the last message is from admin, which is the termination message
|
|
var lastMessage = conversationHistory.Last();
|
|
lastMessage.From.Should().Be("admin");
|
|
lastMessage.IsGroupChatTerminateMessage().Should().BeTrue();
|
|
lastMessage.Should().BeOfType<TextMessage>();
|
|
lastMessage.GetContent().Should().Contain(the39thFibonacciNumber.ToString());
|
|
#endregion create_group_chat
|
|
}
|
|
}
|