133 lines
4.6 KiB
C#
Raw Normal View History

2025-01-27 13:00:05 -05:00
// Copyright (c) Microsoft Corporation. All rights reserved.
2025-01-27 13:05:25 -05:00
// BaseAgent.cs
2025-01-27 13:00:05 -05:00
using System.Diagnostics;
using System.Reflection;
2025-01-27 15:35:06 -05:00
using Microsoft.AutoGen.Contracts;
2025-01-27 13:00:05 -05:00
using Microsoft.Extensions.Logging;
2025-01-27 15:35:06 -05:00
namespace Microsoft.AutoGen.Core;
2025-01-27 13:00:05 -05:00
/// <summary>
/// Represents the base class for an agent in the AutoGen system.
/// </summary>
public abstract class BaseAgent : IAgent, IHostableAgent
{
/// <summary>
/// The activity source for tracing.
/// </summary>
public static readonly ActivitySource s_source = new("Microsoft.AutoGen.Core.Agent");
/// <summary>
/// Gets the unique identifier of the agent.
/// </summary>
public AgentId Id { get; private set; }
2025-01-27 14:35:19 -05:00
protected internal ILogger<BaseAgent> _logger;
2025-01-27 13:00:05 -05:00
public Type[] HandledTypes {
get {
return _handlersByMessageType.Keys.ToArray();
}
}
protected IUnboundSubscriptionDefinition[] GetUnboundSubscriptions()
{
throw new NotImplementedException();
}
protected IAgentRuntime Runtime { get; private set; }
private readonly Dictionary<Type, MethodInfo> _handlersByMessageType;
protected string Description { get; private set; }
public AgentMetadata Metadata {
get {
return new AgentMetadata
{
Type = Id.Type,
Key = Id.Key,
Description = Description
};
}
}
protected BaseAgent(
AgentId id,
IAgentRuntime runtime,
string description,
2025-01-27 14:35:19 -05:00
ILogger<BaseAgent>? logger = null)
2025-01-27 13:00:05 -05:00
{
Id = id;
2025-01-27 14:35:19 -05:00
_logger = logger ?? LoggerFactory.Create(builder => { }).CreateLogger<BaseAgent>();
2025-01-27 13:00:05 -05:00
Description = description;
Runtime = runtime;
_handlersByMessageType = new(GetType().GetHandlersLookupTable());
}
2025-01-27 15:35:06 -05:00
public async ValueTask<object?> OnMessageAsync(object message, MessageContext messageContext)
2025-01-27 13:00:05 -05:00
{
// Determine type of message, then get handler method and invoke it
var messageType = message.GetType();
if (_handlersByMessageType.TryGetValue(messageType, out var handlerMethod))
{
// Determine if this is a IHandle<T> or IHandle<T, U> method
2025-01-27 16:09:05 -05:00
// We need to check if return type is a bare ValueTask or ValueTask<T>
var ret = handlerMethod.ReturnType;
var genericArguments = ret.GetGenericArguments();
// The non-returning type uses ValueTask
if (genericArguments.Length == 0)
2025-01-27 13:00:05 -05:00
{
// This is a IHandle<T> method
var return_value = handlerMethod.Invoke(this, new object[] { message, messageContext });
2025-01-27 15:35:06 -05:00
if (return_value != null){
await (ValueTask)return_value;
}
return ValueTask.CompletedTask;
2025-01-27 13:00:05 -05:00
}
2025-01-27 16:09:05 -05:00
// The returning type uses ValueTask<T>
else if (genericArguments.Length == 1)
2025-01-27 13:00:05 -05:00
{
// This is a IHandle<T, U> method
// var _messageType = genericArguments[0];
// var _returnType = genericArguments[1];
var result = handlerMethod.Invoke(this, new object[] { message, messageContext });
2025-01-27 15:35:06 -05:00
if (result != null){
return await (ValueTask<object?>)result;
}
2025-01-27 13:00:05 -05:00
2025-01-27 15:35:06 -05:00
throw new InvalidOperationException($"Got null result from handler method {handlerMethod.Name}");
2025-01-27 13:00:05 -05:00
}
else
{
2025-01-27 15:35:06 -05:00
throw new InvalidOperationException($"Unexpected number of generic arguments in handler method {handlerMethod.Name}");
2025-01-27 13:00:05 -05:00
}
}
else
{
2025-01-27 15:35:06 -05:00
throw new InvalidOperationException($"No handler found for message type {messageType.FullName}");
2025-01-27 13:00:05 -05:00
}
}
2025-01-27 14:35:19 -05:00
public virtual ValueTask<IDictionary<string, object>> SaveStateAsync()
2025-01-27 13:00:05 -05:00
{
2025-01-27 14:35:19 -05:00
return ValueTask.FromResult<IDictionary<string, object>>(new Dictionary<string, object>());
2025-01-27 13:00:05 -05:00
}
2025-01-27 14:35:19 -05:00
public virtual ValueTask LoadStateAsync(IDictionary<string, object> state)
2025-01-27 13:00:05 -05:00
{
2025-01-27 14:35:19 -05:00
return ValueTask.CompletedTask;
2025-01-27 13:00:05 -05:00
}
public ValueTask<object?> SendMessageAsync(object message, AgentId recepient, string? messageId = null, CancellationToken? cancellationToken = default)
2025-01-27 13:00:05 -05:00
{
return this.Runtime.SendMessageAsync(message, recepient, sender: this.Id, messageId: messageId, cancellationToken: cancellationToken);
}
public ValueTask PublishMessageAsync(object message, TopicId topic, string? messageId = null, CancellationToken? cancellationToken = default)
2025-01-27 13:00:05 -05:00
{
return this.Runtime.PublishMessageAsync(message, topic, sender: this.Id, messageId: messageId, cancellationToken: cancellationToken);
}
}