autogen/dotnet/samples/Hello/HelloAgent
Jacob Alber 8029572f3f
fix: Unhandled Messages should not error when no deserializer is found (#5549)
Right now if a remote agent sends a message that local agents do not
listen to (and thus will never configure a deserializer for), or if the
first agent in the iteration is one such, the runtime will throw an
unnecessary exception an come down, even though the deserialized message
will never actually be needed before a deserializer is registered.

The fix will downgrade that to a warning.

* Also updates the HelloAgent sample to be more amenable to being used
with gRPC directly, without configuring environment variables.
2025-02-14 10:27:29 -05:00
..
Properties Do not exclude Properties or appsettings.json via .gitignore, commit missing files (#4057) 2024-11-04 20:48:46 +01:00
HelloAgent.cs fix: Switch HelloAgent to use agent_events.proto from the Agents project (#5512) 2025-02-12 18:37:42 -05:00
HelloAgent.csproj Improve e2e integration tests and isolate tests from other things; includes patch to Serializer (#5497) 2025-02-13 16:43:57 -08:00
Program.cs fix: Unhandled Messages should not error when no deserializer is found (#5549) 2025-02-14 10:27:29 -05:00
README.md rysweet-unsubscribe-and-agent-tests-4744 (#4920) 2025-01-24 19:24:00 -08:00
appsettings.json Rysweet fix integration tests and xlang (#5107) 2025-01-20 18:06:06 +00:00

README.md

AutoGen 0.4 .NET Hello World Sample

This sample demonstrates how to create a simple .NET console application that listens for an event and then orchestrates a series of actions in response.

Prerequisites

To run this sample, you'll need: .NET 8.0 or later. Also recommended is the GitHub CLI.

Instructions to run the sample

# Clone the repository
gh repo clone microsoft/autogen
cd dotnet/samples/Hello
dotnet run

Key Concepts

This sample illustrates how to create your own agent that inherits from a base agent and listens for an event. It also shows how to use the SDK's App Runtime locally to start the agent and send messages.

Flow Diagram:

%%{init: {'theme':'forest'}}%%
graph LR;
    A[Main] --> |"PublishEventAsync(NewMessage('World'))"| B{"Handle(NewMessageReceived item, CancellationToken cancellationToken = default)"}
    B --> |"PublishEventAsync(Output('***Hello, World***'))"| C[ConsoleAgent]
    C --> D{"WriteConsole()"}
    B --> |"PublishEventAsync(ConversationClosed('Goodbye'))"| E{"Handle(ConversationClosed item, CancellationToken cancellationToken = default)"}
    B --> |"PublishEventAsync(Output('***Goodbye***'))"| C
    E --> F{"Shutdown()"}

Writing Event Handlers

The heart of an autogen application are the event handlers. Agents select a TopicSubscription to listen for events on a specific topic. When an event is received, the agent's event handler is called with the event data.

Within that event handler you may optionally emit new events, which are then sent to the event bus for other agents to process. The EventTypes are declared gRPC ProtoBuf messages that are used to define the schema of the event. The default protos are available via the Microsoft.AutoGen.Contracts; namespace and are defined in autogen/protos. The EventTypes are registered in the agent's constructor using the IHandle interface.

TopicSubscription("HelloAgents")]
public class HelloAgent(
    iAgentWorker worker,
    [FromKeyedServices("AgentsMetadata")] AgentsMetadata typeRegistry) : ConsoleAgent(
        worker,
        typeRegistry),
        ISayHello,
        IHandle<NewMessageReceived>,
        IHandle<ConversationClosed>
{
    public async Task Handle(NewMessageReceived item, CancellationToken cancellationToken = default)
    {
        var response = await SayHello(item.Message).ConfigureAwait(false);
        var evt = new Output
        {
            Message = response
        }.ToCloudEvent(this.AgentId.Key);
        await PublishEventAsync(evt).ConfigureAwait(false);
        var goodbye = new ConversationClosed
        {
            UserId = this.AgentId.Key,
            UserMessage = "Goodbye"
        }.ToCloudEvent(this.AgentId.Key);
        await PublishEventAsync(goodbye).ConfigureAwait(false);
    }

Inheritance and Composition

This sample also illustrates inheritance in AutoGen. The HelloAgent class inherits from ConsoleAgent, which is a base class that provides a WriteConsole method.

Starting the Application Runtime

AuotoGen provides a flexible runtime Microsoft.AutoGen.Agents.App that can be started in a variety of ways. The Program.cs file demonstrates how to start the runtime locally and send a message to the agent all in one go using the App.PublishMessageAsync method.

// send a message to the agent
var app = await App.PublishMessageAsync("HelloAgents", new NewMessageReceived
{
    Message = "World"
}, local: true);

await App.RuntimeApp!.WaitForShutdownAsync();
await app.WaitForShutdownAsync();

Sending Messages

The set of possible Messages is defined in gRPC ProtoBuf specs. These are then turned into C# classes by the gRPC tools. You can define your own Message types by creating a new .proto file in your project and including the gRPC tools in your .csproj file:

syntax = "proto3";
package devteam;
option csharp_namespace = "DevTeam.Shared";
message NewAsk {
  string org = 1;
  string repo = 2;
  string ask = 3;
  int64 issue_number = 4;
}
message ReadmeRequested {
   string org = 1;
   string repo = 2;
   int64 issue_number = 3;
   string ask = 4;
}
  <ItemGroup>
    <PackageReference Include="Google.Protobuf" />
    <PackageReference Include="Grpc.Tools" PrivateAssets="All" />
    <Protobuf Include="..\Protos\messages.proto" Link="Protos\messages.proto" />
  </ItemGroup>

You can send messages using the Microsoft.AutoGen.Agents.AgentWorker class. Messages are wrapped in the CloudEvents specification and sent to the event bus.