Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
205 commits
Select commit Hold shift + click to select a range
ed2bd33
Agent framework
crickman Mar 30, 2024
33f1c0e
Project structure
crickman Mar 31, 2024
ca4c1a6
Readme cleanup
crickman Mar 31, 2024
d58e416
Build
crickman Mar 31, 2024
74d8deb
Tests and examples
crickman Mar 31, 2024
de71d83
Test coverage
crickman Mar 31, 2024
5236c28
Update tests
crickman Mar 31, 2024
308d4b8
Spelling
crickman Mar 31, 2024
905e438
Namespace
crickman Mar 31, 2024
d86380d
Coverage
crickman Mar 31, 2024
4273aae
PlugIn Example
crickman Apr 1, 2024
2a1aba2
Merge branch 'main' into feature_agent_framework
crickman Apr 1, 2024
bd98124
Test comments & clean-up
crickman Apr 1, 2024
070f82d
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 1, 2024
ca53ecd
MVP
crickman Apr 1, 2024
fbdf862
Format Fix
crickman Apr 1, 2024
72b720e
Remove System.Linq.Async
crickman Apr 1, 2024
425af3c
Build GD
crickman Apr 1, 2024
000f079
Rollback
crickman Apr 1, 2024
e7d365a
Merge branch 'main' into feature_agent_framework
crickman Apr 1, 2024
6a4fb99
Build plz
crickman Apr 1, 2024
4e880e3
Format
crickman Apr 1, 2024
1e01292
Project form
crickman Apr 1, 2024
264cc82
Extra instructions
crickman Apr 1, 2024
f3c54c4
ChatCompletionAgent UT
crickman Apr 1, 2024
0e44caf
Coverage
crickman Apr 1, 2024
7225767
Coverage
crickman Apr 1, 2024
22fc872
TODO - Render Filters
crickman Apr 1, 2024
6416ea6
Experiment def
crickman Apr 1, 2024
7dbe37a
Bootstrap AgentChat
crickman Apr 1, 2024
ba16b05
Fix experiments
crickman Apr 2, 2024
2ac41f0
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 2, 2024
8ba1c91
Introducing AgentChat
crickman Apr 2, 2024
42e0bcd
Comment
crickman Apr 2, 2024
56bc185
Tuning
crickman Apr 2, 2024
2cc1686
Merge branch 'main' into feature_agent_framework
crickman Apr 2, 2024
aa7231c
Spelling
crickman Apr 2, 2024
01c7d85
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 2, 2024
8f99aa6
TODO Comments
crickman Apr 2, 2024
9048a69
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 2, 2024
cd5ed82
Example
crickman Apr 2, 2024
7977d0a
Spelling
crickman Apr 2, 2024
b931c48
More tests
crickman Apr 2, 2024
f334ccc
Merge branch 'main' into feature_agent_framework
crickman Apr 2, 2024
f57d1ca
Refine
crickman Apr 2, 2024
75fc135
Merge branch 'main' into feature_agent_framework
crickman Apr 2, 2024
ac090fd
Merge branch 'main' into feature_agent_framework
crickman Apr 2, 2024
dec0de2
Checkpoint
crickman Apr 2, 2024
0984733
Less experiment ids
crickman Apr 2, 2024
f8a8365
Identity
crickman Apr 2, 2024
4f436a3
Merge from main
crickman Apr 2, 2024
0438231
Update test
crickman Apr 2, 2024
737cd2f
Test checkpoint
crickman Apr 3, 2024
acc0d2a
Encoder fix
crickman Apr 3, 2024
180d37d
Encoder2
crickman Apr 3, 2024
713d20c
Test cleanup
crickman Apr 3, 2024
7fe0af3
Needs unit test
crickman Apr 3, 2024
afde6b3
Yeah
crickman Apr 3, 2024
ab1383c
BroadcastQueue Failure Propagation
crickman Apr 3, 2024
fdedc20
Merge branch 'main' into feature_agent_framework
crickman Apr 3, 2024
7144324
Update from PR Comments
crickman Apr 3, 2024
cc5c211
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 3, 2024
143394b
Merge branch 'main' into feature_agent_framework
crickman Apr 3, 2024
8908968
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 3, 2024
a562a7e
Merged from main
crickman Apr 3, 2024
6277f59
Fix merge
crickman Apr 3, 2024
c0a62d0
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 3, 2024
ffeeeff
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 3, 2024
1aa05cd
Fix merge
crickman Apr 3, 2024
e9736ec
Namespace
crickman Apr 3, 2024
4466048
Coverage
crickman Apr 3, 2024
5a021a8
Update from PR comments
crickman Apr 3, 2024
8dfcf5d
PR Comments
crickman Apr 3, 2024
c1dae3f
Resolve merge
crickman Apr 3, 2024
60fe17f
Typo
crickman Apr 3, 2024
dd50899
Cleanup
crickman Apr 3, 2024
c22176f
Merge branch 'main' into feature_agent_framework
crickman Apr 3, 2024
10823e2
Heck ya
crickman Apr 4, 2024
104ebbd
Fix
crickman Apr 4, 2024
5587125
Termination Strategies
crickman Apr 4, 2024
07c9774
Ack
crickman Apr 4, 2024
9a2b4e2
Strategies
crickman Apr 4, 2024
c17fcb4
Merge branch 'main' into feature_agent_framework
crickman Apr 4, 2024
c58191c
CancellationToken default
crickman Apr 4, 2024
7ac3051
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 4, 2024
16b438b
Merge branch 'main' into feature_agent_framework
crickman Apr 4, 2024
92b9da7
Merge branch 'main' into feature_agent_framework
crickman Apr 4, 2024
0878281
Merge branch 'main' into feature_agent_framework
crickman Apr 4, 2024
734656e
Type/concept rename
crickman Apr 4, 2024
769d658
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 4, 2024
70871f9
Latest and greatest
crickman Apr 4, 2024
b9706e4
Nexus scrub
crickman Apr 4, 2024
5436fed
Abstraction rename
crickman Apr 4, 2024
c2020fd
One more (Abstractions folder name)
crickman Apr 4, 2024
de2dad0
Remove connector dependency
crickman Apr 4, 2024
e2860cc
Re-add connector reference downstream
crickman Apr 4, 2024
adf0bee
Review
crickman Apr 4, 2024
af41586
Comment
crickman Apr 4, 2024
73079ed
Comments
crickman Apr 4, 2024
6b7a0b7
Support 'init'
crickman Apr 4, 2024
df620ef
Resolve merge
crickman Apr 4, 2024
a463b36
AgentGroupChat
crickman Apr 4, 2024
2e60f01
Clean
crickman Apr 4, 2024
e46cf2d
Comment
crickman Apr 4, 2024
503dd98
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 4, 2024
4a0dd62
Nuget description
crickman Apr 4, 2024
9a2c957
Nuget
crickman Apr 4, 2024
0482a96
Assembly naming
crickman Apr 4, 2024
90e642a
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 4, 2024
69ec8c6
Build
crickman Apr 4, 2024
6d446c7
Build
crickman Apr 4, 2024
d5be2ca
Comments
crickman Apr 4, 2024
75226d2
Merge branch 'main' into feature_agent_framework
crickman Apr 5, 2024
9478524
Comments Checkpoint
crickman Apr 7, 2024
6fe407e
Dead code
crickman Apr 7, 2024
1143f5a
More comments + typo
crickman Apr 7, 2024
5d37582
More PR updates
crickman Apr 7, 2024
9479b49
Don't copy
crickman Apr 7, 2024
f8d758c
Blank line
crickman Apr 7, 2024
b7f35f7
Merge from feature
crickman Apr 7, 2024
b711530
More
crickman Apr 7, 2024
14929f0
Namespace
crickman Apr 7, 2024
e6c6991
public => private: perfect
crickman Apr 7, 2024
0e8b981
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 7, 2024
b06b7e2
Remove namespace
crickman Apr 7, 2024
b6566ff
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 7, 2024
8291e0f
init KernelArguments
crickman Apr 7, 2024
d8f4c2e
Signatures
crickman Apr 7, 2024
510751f
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 7, 2024
822f494
Test fix
crickman Apr 7, 2024
b3da6a6
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 7, 2024
46f7060
Build
crickman Apr 7, 2024
23395cf
Fix mock
crickman Apr 7, 2024
546e5f0
Merge branch 'main' into feature_agent_framework
crickman Apr 8, 2024
83613aa
Sans templatization
crickman Apr 8, 2024
e7f2294
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 8, 2024
bbe584b
Namespace
crickman Apr 8, 2024
09677a2
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 8, 2024
6a13d00
Merge branch 'main' into feature_agent_framework
crickman Apr 8, 2024
7f98506
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 8, 2024
2585798
Rename local function for agent example
crickman Apr 9, 2024
0ad4b0b
Remove `AddUserMessage`
crickman Apr 9, 2024
919b8f8
Test fix
crickman Apr 9, 2024
1fc19eb
Merge branch 'main' into feature_agent_framework
crickman Apr 9, 2024
031c28a
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 9, 2024
865b725
Update project/package reference
crickman Apr 9, 2024
5e47fb5
Remove constructors
crickman Apr 9, 2024
5ef126b
Spelling
crickman Apr 9, 2024
d47271b
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 9, 2024
6556a25
Use real AgentChat in examples
crickman Apr 9, 2024
28a3428
Namespace
crickman Apr 9, 2024
3f87008
Namespace
crickman Apr 9, 2024
8c8da67
Channel comment clarification
crickman Apr 9, 2024
a8ee4cf
Merge branch 'main' into feature_agent_framework
crickman Apr 9, 2024
811b100
Agent examples build directive clean-up
crickman Apr 10, 2024
4595945
Merge branch 'feature_agent_framework' of https://github.com/microsof…
crickman Apr 10, 2024
270590e
Merge branch 'feature_agent_framework' into feature_agent_chat
crickman Apr 10, 2024
b45dc56
Resolve merge
crickman Apr 10, 2024
4c3c2ae
Namespace / Merge fix
crickman Apr 10, 2024
0bd61fd
Last merge fix
crickman Apr 10, 2024
f7cf4e1
Merge branch 'main' into feature_agent_chat
crickman Apr 10, 2024
948cea7
Merge branch 'main' into feature_agent_chat
crickman Apr 11, 2024
6ef5dbc
Merge branch 'main' into feature_agent_chat
crickman Apr 11, 2024
45abc89
First update from PR comments.
crickman Apr 11, 2024
88f59e3
Consolidate AgentBoundTerminationStrategy contract
crickman Apr 11, 2024
59d13e4
Typos and namespaces
crickman Apr 11, 2024
639a4de
SequentialSelectionStrategy.Reset()
crickman Apr 11, 2024
4d3418d
Blank line
crickman Apr 11, 2024
40d22bd
Removed null defaults for execution settings / strategies
crickman Apr 11, 2024
2e8eb1c
Typos
crickman Apr 11, 2024
31778cc
Namespace
crickman Apr 11, 2024
6d7baa0
Merge branch 'main' into feature_agent_chat
crickman Apr 11, 2024
4c4729d
Throw on no selection-strategy
crickman Apr 11, 2024
0dd303c
Selection failure contract
crickman Apr 11, 2024
9ab4130
Reset termination / iscomplete option
crickman Apr 11, 2024
cb843b9
Clean
crickman Apr 11, 2024
616366d
Clean-up
crickman Apr 11, 2024
28e37f1
Improvement
crickman Apr 11, 2024
7b73c4c
dotnet version for UT
crickman Apr 11, 2024
758bfd3
Merge branch 'main' into feature_agent_chat
crickman Apr 12, 2024
6158c97
ConfigureAwait
crickman Apr 12, 2024
5c9ae72
Merge branch 'feature_agent_chat' of https://github.com/microsoft/sem…
crickman Apr 12, 2024
3952a0c
Merge from main
crickman Apr 15, 2024
cc7291d
Fix merge
crickman Apr 15, 2024
7f6d04e
Clean-up
crickman Apr 15, 2024
11db2b6
Namespace
crickman Apr 15, 2024
bdceeb5
Update example
crickman Apr 15, 2024
f79a086
Lil' luv
crickman Apr 15, 2024
2a75117
Onward
crickman Apr 15, 2024
10d6578
Merge branch 'main' into feature_agent_chat
crickman Apr 16, 2024
af9a6b3
Merge branch 'main' into feature_agent_chat
crickman Apr 16, 2024
01ec7d6
Merge branch 'main' into feature_agent_chat
crickman Apr 16, 2024
cfd2337
Comments
crickman Apr 16, 2024
eeb5317
Merge branch 'feature_agent_chat' of https://github.com/microsoft/sem…
crickman Apr 16, 2024
d5c3ff6
SelectionStrategy default
crickman Apr 16, 2024
0f4418e
Iterating on max-turns
crickman Apr 16, 2024
971b7e6
Namespace
crickman Apr 16, 2024
f85ff03
Backport fix
crickman Apr 16, 2024
1e261fb
Merge branch 'main' into feature_agent_chat
crickman Apr 17, 2024
5664b84
Test rename
crickman Apr 17, 2024
218b97f
Comment
crickman Apr 17, 2024
683cb15
set => init
crickman Apr 17, 2024
8c393b5
Merge branch 'main' into feature_agent_chat
crickman Apr 17, 2024
ef71f35
Comment
crickman Apr 17, 2024
081cb77
Merge branch 'feature_agent_chat' of https://github.com/microsoft/sem…
crickman Apr 17, 2024
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
18 changes: 1 addition & 17 deletions dotnet/samples/AgentSyntaxExamples/Example01_Agent.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
Expand Down Expand Up @@ -32,7 +30,7 @@ public async Task RunAsync()
};

// Create a chat for agent interaction. For more, see: Example03_Chat.
var chat = new TestChat();
AgentGroupChat chat = new();

// Respond to user input
await InvokeAgentAsync("Fortune favors the bold.");
Expand All @@ -52,18 +50,4 @@ async Task InvokeAgentAsync(string input)
}
}
}

/// <summary>
/// A simple chat for the agent example.
/// </summary>
/// <remarks>
/// For further exploration of <see cref="AgentChat"/>, see: Example03_Chat.
/// </remarks>
private sealed class TestChat : AgentChat
{
public IAsyncEnumerable<ChatMessageContent> InvokeAsync(
Agent agent,
CancellationToken cancellationToken = default) =>
base.InvokeAgentAsync(agent, cancellationToken);
}
}
19 changes: 1 addition & 18 deletions dotnet/samples/AgentSyntaxExamples/Example02_Plugins.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
Expand Down Expand Up @@ -39,7 +37,7 @@ public async Task RunAsync()
agent.Kernel.Plugins.Add(plugin);

// Create a chat for agent interaction. For more, see: Example03_Chat.
var chat = new TestChat();
AgentGroupChat chat = new();

// Respond to user input, invoking functions where appropriate.
await InvokeAgentAsync("Hello");
Expand All @@ -59,19 +57,4 @@ async Task InvokeAgentAsync(string input)
}
}
}

/// <summary>
///
/// A simple chat for the agent example.
/// </summary>
/// <remarks>
/// For further exploration of <see cref="AgentChat"/>, see: Example03_Chat.
/// </remarks>
private sealed class TestChat : AgentChat
{
public IAsyncEnumerable<ChatMessageContent> InvokeAsync(
Agent agent,
CancellationToken cancellationToken = default) =>
base.InvokeAgentAsync(agent, cancellationToken);
}
}
97 changes: 97 additions & 0 deletions dotnet/samples/AgentSyntaxExamples/Example03_Chat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Agents;
using Microsoft.SemanticKernel.Agents.Chat;
using Microsoft.SemanticKernel.ChatCompletion;
using Xunit;
using Xunit.Abstractions;

namespace Examples;

/// <summary>
/// Demonstrate creation of <see cref="AgentChat"/> with <see cref="AgentGroupChatSettings"/>
/// that inform how chat proceeds with regards to: Agent selection, chat continuation, and maximum
/// number of agent interactions.
/// </summary>
public class Example03_Chat(ITestOutputHelper output) : BaseTest(output)
{
private const string ReviewerName = "ArtDirector";
private const string ReviewerInstructions =
"""
You are an art director who has opinions about copywriting born of a love for David Ogilvy.
The goal is to determine is the given copy is acceptable to print.
If so, state that it is approved.
If not, provide insight on how to refine suggested copy without example.
""";

private const string CopyWriterName = "Writer";
private const string CopyWriterInstructions =
"""
You are a copywriter with ten years of experience and are known for brevity and a dry humor.
You're laser focused on the goal at hand. Don't waste time with chit chat.
The goal is to refine and decide on the single best copy as an expert in the field.
Consider suggestions when refining an idea.
""";

[Fact]
public async Task RunAsync()
{
// Define the agents
ChatCompletionAgent agentReviewer =
new()
{
Instructions = ReviewerInstructions,
Name = ReviewerName,
Kernel = this.CreateKernelWithChatCompletion(),
};

ChatCompletionAgent agentWriter =
new()
{
Instructions = CopyWriterInstructions,
Name = CopyWriterName,
Kernel = this.CreateKernelWithChatCompletion(),
};

// Create a chat for agent interaction.
AgentGroupChat chat =
new(agentWriter, agentReviewer)
{
ExecutionSettings =
new()
{
// Here a TerminationStrategy subclass is used that will terminate when
// an assistant message contains the term "approve".
TerminationStrategy =
new ApprovalTerminationStrategy()
{
// Only the art-director may approve.
Agents = [agentReviewer],
}
}
};

// Invoke chat and display messages.
string input = "concept: maps made out of egg cartons.";
chat.AddChatMessage(new ChatMessageContent(AuthorRole.User, input));
this.WriteLine($"# {AuthorRole.User}: '{input}'");

await foreach (var content in chat.InvokeAsync())
{
this.WriteLine($"# {content.Role} - {content.AuthorName ?? "*"}: '{content.Content}'");
}

this.WriteLine($"# IS COMPLETE: {chat.IsComplete}");
}

private sealed class ApprovalTerminationStrategy : TerminationStrategy
{
// Terminate when the final message contains the term "approve"
protected override Task<bool> ShouldAgentTerminateAsync(Agent agent, IReadOnlyList<ChatMessageContent> history, CancellationToken cancellationToken)
=> Task.FromResult(history[history.Count - 1].Content?.Contains("approve", StringComparison.OrdinalIgnoreCase) ?? false);
}
}
18 changes: 11 additions & 7 deletions dotnet/src/Agents/Abstractions/AgentChat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,14 @@ public abstract class AgentChat
private readonly BroadcastQueue _broadcastQueue;
private readonly Dictionary<string, AgentChannel> _agentChannels;
private readonly Dictionary<Agent, string> _channelMap;
private readonly ChatHistory _history;

private int _isActive;

/// <summary>
/// Exposes the internal history to subclasses.
/// </summary>
protected ChatHistory History { get; }

/// <summary>
/// Retrieve the message history, either the primary history or
/// an agent specific version.
Expand All @@ -34,7 +38,7 @@ public IAsyncEnumerable<ChatMessageContent> GetChatMessagesAsync(Agent? agent =
{
if (agent == null)
{
return this._history.ToDescendingAsync();
return this.History.ToDescendingAsync();
}

var channelKey = this.GetAgentHash(agent);
Expand Down Expand Up @@ -80,7 +84,7 @@ public void AddChatMessages(IReadOnlyList<ChatMessageContent> messages)
}

// Append to chat history
this._history.AddRange(messages);
this.History.AddRange(messages);

// Broadcast message to other channels (in parallel)
var channelRefs = this._agentChannels.Select(kvp => new ChannelReference(kvp.Value, kvp.Key));
Expand Down Expand Up @@ -114,7 +118,7 @@ protected async IAsyncEnumerable<ChatMessageContent> InvokeAgentAsync(
await foreach (var message in channel.InvokeAsync(agent, cancellationToken).ConfigureAwait(false))
{
// Add to primary history
this._history.Add(message);
this.History.Add(message);
messages.Add(message);

// Yield message to caller
Expand Down Expand Up @@ -146,9 +150,9 @@ private async Task<AgentChannel> GetChannelAsync(Agent agent, CancellationToken
{
channel = await agent.CreateChannelAsync(cancellationToken).ConfigureAwait(false);

if (this._history.Count > 0)
if (this.History.Count > 0)
{
await channel.ReceiveAsync(this._history, cancellationToken).ConfigureAwait(false);
await channel.ReceiveAsync(this.History, cancellationToken).ConfigureAwait(false);
}

this._agentChannels.Add(channelKey, channel);
Expand Down Expand Up @@ -179,6 +183,6 @@ protected AgentChat()
this._agentChannels = [];
this._broadcastQueue = new();
this._channelMap = [];
this._history = [];
this.History = [];
}
}
148 changes: 148 additions & 0 deletions dotnet/src/Agents/Core/AgentGroupChat.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.SemanticKernel.Agents.Chat;
using Microsoft.SemanticKernel.ChatCompletion;

namespace Microsoft.SemanticKernel.Agents;

/// <summary>
/// A an <see cref="AgentChat"/> that supports multi-turn interactions.
/// </summary>
public sealed class AgentGroupChat : AgentChat
{
private readonly HashSet<string> _agentIds; // Efficient existence test
private readonly List<Agent> _agents; // Maintain order

/// <summary>
/// Indicates if completion criteria has been met. If set, no further
/// agent interactions will occur. Clear to enable more agent interactions.
/// </summary>
public bool IsComplete { get; set; }

/// <summary>
/// Settings for defining chat behavior.
/// </summary>
public AgentGroupChatSettings ExecutionSettings { get; set; } = new AgentGroupChatSettings();

/// <summary>
/// The agents participating in the chat.
/// </summary>
public IReadOnlyList<Agent> Agents => this._agents.AsReadOnly();

/// <summary>
/// Add a <see cref="Agent"/> to the chat.
/// </summary>
/// <param name="agent">The <see cref="KernelAgent"/> to add.</param>
public void AddAgent(Agent agent)
{
if (this._agentIds.Add(agent.Id))
{
this._agents.Add(agent);
}
}

/// <summary>
/// Process a series of interactions between the <see cref="AgentGroupChat.Agents"/> that have joined this <see cref="AgentGroupChat"/>.
/// The interactions will proceed according to the <see cref="SelectionStrategy"/> and the <see cref="TerminationStrategy"/>
/// defined via <see cref="AgentGroupChat.ExecutionSettings"/>.
/// In the absence of an <see cref="AgentGroupChatSettings.SelectionStrategy"/>, this method will not invoke any agents.
/// Any agent may be explicitly selected by calling <see cref="AgentGroupChat.InvokeAsync(Agent, bool, CancellationToken)"/>.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>Asynchronous enumeration of messages.</returns>
public async IAsyncEnumerable<ChatMessageContent> InvokeAsync([EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (this.IsComplete)
{
// Throw exception if chat is completed and automatic-reset is not enabled.
if (!this.ExecutionSettings.TerminationStrategy.AutomaticReset)
{
throw new KernelException("Agent Failure - Chat has completed.");
}

this.IsComplete = false;
}

for (int index = 0; index < this.ExecutionSettings.TerminationStrategy.MaximumIterations; index++)
{
// Identify next agent using strategy
Agent agent = await this.ExecutionSettings.SelectionStrategy.NextAsync(this.Agents, this.History, cancellationToken).ConfigureAwait(false);

// Invoke agent and process messages along with termination
await foreach (var message in base.InvokeAgentAsync(agent, cancellationToken).ConfigureAwait(false))
{
if (message.Role == AuthorRole.Assistant)
{
var task = this.ExecutionSettings.TerminationStrategy.ShouldTerminateAsync(agent, this.History, cancellationToken);
this.IsComplete = await task.ConfigureAwait(false);
}

yield return message;
}

if (this.IsComplete)
{
break;
}
}
}

/// <summary>
/// Process a single interaction between a given <see cref="Agent"/> an a <see cref="AgentGroupChat"/>.
/// </summary>
/// <param name="agent">The agent actively interacting with the chat.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>Asynchronous enumeration of messages.</returns>
/// <remark>
/// Specified agent joins the chat.
/// </remark>>
public IAsyncEnumerable<ChatMessageContent> InvokeAsync(
Agent agent,
CancellationToken cancellationToken = default) =>
this.InvokeAsync(agent, isJoining: true, cancellationToken);

/// <summary>
/// Process a single interaction between a given <see cref="KernelAgent"/> an a <see cref="AgentGroupChat"/> irregardless of
/// the <see cref="SelectionStrategy"/> defined via <see cref="AgentGroupChat.ExecutionSettings"/>. Likewise, this does
/// not regard <see cref="TerminationStrategy.MaximumIterations"/> as it only takes a single turn for the specified agent.
/// </summary>
/// <param name="agent">The agent actively interacting with the chat.</param>
/// <param name="isJoining">Optional flag to control if agent is joining the chat.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
/// <returns>Asynchronous enumeration of messages.</returns>
public async IAsyncEnumerable<ChatMessageContent> InvokeAsync(
Agent agent,
bool isJoining,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
if (isJoining)
{
this.AddAgent(agent);
}

await foreach (var message in base.InvokeAgentAsync(agent, cancellationToken).ConfigureAwait(false))
{
if (message.Role == AuthorRole.Assistant)
{
var task = this.ExecutionSettings.TerminationStrategy.ShouldTerminateAsync(agent, this.History, cancellationToken);
this.IsComplete = await task.ConfigureAwait(false);
}

yield return message;
}
}

/// <summary>
/// Initializes a new instance of the <see cref="AgentGroupChat"/> class.
/// </summary>
/// <param name="agents">The agents initially participating in the chat.</param>
public AgentGroupChat(params Agent[] agents)
{
this._agents = new(agents);
this._agentIds = new(this._agents.Select(a => a.Id));
}
}
Loading