// Copyright (c) Microsoft. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Microsoft.Extensions.AI.Agents.Runtime;
///
/// Internal implementation of that manages actor type registrations
/// and their associated factory methods for the actor runtime system.
///
internal sealed class ActorRuntimeBuilder : IActorRuntimeBuilder
{
private readonly IHostApplicationBuilder _builder;
///
/// Gets the collection of registered actor types and their corresponding factory methods.
///
///
/// A dictionary where keys are instances and values are factory functions
/// that create instances given an and .
///
public Dictionary> ActorFactories { get; } = new();
///
/// Gets or creates an instance for the specified host application builder.
/// If an instance already exists in the service collection, it returns the existing instance.
/// Otherwise, it creates a new instance and registers it as a singleton service.
///
/// The host application builder to associate with the actor runtime builder.
///
/// An instance that can be used to configure actor types.
///
/// Thrown when is null.
public static ActorRuntimeBuilder GetOrAdd(IHostApplicationBuilder builder)
{
Microsoft.Shared.Diagnostics.Throw.IfNull(builder);
var services = builder.Services;
var descriptor = services.FirstOrDefault(s => s.ImplementationInstance is ActorRuntimeBuilder);
if (descriptor?.ImplementationInstance is not ActorRuntimeBuilder instance)
{
instance = new ActorRuntimeBuilder(builder);
services.Add(ServiceDescriptor.Singleton(instance));
instance.ConfigureServices(services);
}
return instance;
}
///
/// Initializes a new instance of the class.
///
/// The host application builder to associate with this actor runtime builder.
private ActorRuntimeBuilder(IHostApplicationBuilder builder)
{
this._builder = builder;
}
///
/// Registers an actor type with its factory method in the actor runtime.
///
/// The actor type to register.
///
/// The factory method that creates instances of the actor. This function receives an
/// for dependency injection and an
/// for the actor's runtime context, and returns an instance.
///
///
/// Thrown when an actor type with the same name is already registered.
///
///
/// Each actor type can only be registered once. Attempting to register the same actor type
/// multiple times will result in an exception being thrown by the underlying dictionary.
///
public void AddActorType(ActorType type, Func activator)
{
this.ActorFactories.Add(type, activator);
}
private void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(this);
services.AddSingleton();
services.AddSingleton();
services.AddSingleton(sp =>
{
var jsonSerializerOptions = sp.GetService() ?? new();
var actorStateStorage = sp.GetRequiredService();
return new InProcessActorRuntime(sp, this.ActorFactories, actorStateStorage, jsonSerializerOptions);
});
}
}