Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,67 @@ public static class ChatClientBuilderServiceCollectionExtensions
/// <summary>Registers a singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the client should be added.</param>
/// <param name="innerClient">The inner <see cref="IChatClient"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>A <see cref="ChatClientBuilder"/> that can be used to build a pipeline around the inner client.</returns>
/// <remarks>The client is registered as a singleton service.</remarks>
public static ChatClientBuilder AddChatClient(
this IServiceCollection serviceCollection,
IChatClient innerClient)
=> AddChatClient(serviceCollection, _ => innerClient);
IChatClient innerClient,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
=> AddChatClient(serviceCollection, _ => innerClient, lifetime);

/// <summary>Registers a singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the client should be added.</param>
/// <param name="innerClientFactory">A callback that produces the inner <see cref="IChatClient"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>A <see cref="ChatClientBuilder"/> that can be used to build a pipeline around the inner client.</returns>
/// <remarks>The client is registered as a singleton service.</remarks>
public static ChatClientBuilder AddChatClient(
this IServiceCollection serviceCollection,
Func<IServiceProvider, IChatClient> innerClientFactory)
Func<IServiceProvider, IChatClient> innerClientFactory,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
_ = Throw.IfNull(serviceCollection);
_ = Throw.IfNull(innerClientFactory);

var builder = new ChatClientBuilder(innerClientFactory);
_ = serviceCollection.AddSingleton(builder.Build);
serviceCollection.Add(new ServiceDescriptor(typeof(IChatClient), builder.Build, lifetime));
return builder;
}

/// <summary>Registers a keyed singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the client should be added.</param>
/// <param name="serviceKey">The key with which to associate the client.</param>
/// <param name="innerClient">The inner <see cref="IChatClient"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>A <see cref="ChatClientBuilder"/> that can be used to build a pipeline around the inner client.</returns>
/// <remarks>The client is registered as a scoped service.</remarks>
public static ChatClientBuilder AddKeyedChatClient(
this IServiceCollection serviceCollection,
object serviceKey,
IChatClient innerClient)
=> AddKeyedChatClient(serviceCollection, serviceKey, _ => innerClient);
IChatClient innerClient,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
=> AddKeyedChatClient(serviceCollection, serviceKey, _ => innerClient, lifetime);

/// <summary>Registers a keyed singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the client should be added.</param>
/// <param name="serviceKey">The key with which to associate the client.</param>
/// <param name="innerClientFactory">A callback that produces the inner <see cref="IChatClient"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>A <see cref="ChatClientBuilder"/> that can be used to build a pipeline around the inner client.</returns>
/// <remarks>The client is registered as a scoped service.</remarks>
public static ChatClientBuilder AddKeyedChatClient(
this IServiceCollection serviceCollection,
object serviceKey,
Func<IServiceProvider, IChatClient> innerClientFactory)
Func<IServiceProvider, IChatClient> innerClientFactory,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
_ = Throw.IfNull(serviceCollection);
_ = Throw.IfNull(serviceKey);
_ = Throw.IfNull(innerClientFactory);

var builder = new ChatClientBuilder(innerClientFactory);
_ = serviceCollection.AddKeyedSingleton(serviceKey, (services, _) => builder.Build(services));
serviceCollection.Add(new ServiceDescriptor(typeof(IChatClient), serviceKey, factory: (services, serviceKey) => builder.Build(services), lifetime));
return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,31 +15,35 @@ public static class EmbeddingGeneratorBuilderServiceCollectionExtensions
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
/// <param name="innerGenerator">The inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
/// <remarks>The generator is registered as a singleton service.</remarks>
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddEmbeddingGenerator<TInput, TEmbedding>(
this IServiceCollection serviceCollection,
IEmbeddingGenerator<TInput, TEmbedding> innerGenerator)
IEmbeddingGenerator<TInput, TEmbedding> innerGenerator,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TEmbedding : Embedding
=> AddEmbeddingGenerator(serviceCollection, _ => innerGenerator);
=> AddEmbeddingGenerator(serviceCollection, _ => innerGenerator, lifetime);

/// <summary>Registers a singleton embedding generator in the <see cref="IServiceCollection"/>.</summary>
/// <typeparam name="TInput">The type from which embeddings will be generated.</typeparam>
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
/// <param name="innerGeneratorFactory">A callback that produces the inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
/// <remarks>The generator is registered as a singleton service.</remarks>
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddEmbeddingGenerator<TInput, TEmbedding>(
this IServiceCollection serviceCollection,
Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory)
Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TEmbedding : Embedding
{
_ = Throw.IfNull(serviceCollection);
_ = Throw.IfNull(innerGeneratorFactory);

var builder = new EmbeddingGeneratorBuilder<TInput, TEmbedding>(innerGeneratorFactory);
_ = serviceCollection.AddSingleton(builder.Build);
serviceCollection.Add(new ServiceDescriptor(typeof(IEmbeddingGenerator<TInput, TEmbedding>), builder.Build, lifetime));
return builder;
}

Expand All @@ -49,35 +53,39 @@ public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddEmbeddingGenerato
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
/// <param name="serviceKey">The key with which to associated the generator.</param>
/// <param name="innerGenerator">The inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
/// <remarks>The generator is registered as a singleton service.</remarks>
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddKeyedEmbeddingGenerator<TInput, TEmbedding>(
this IServiceCollection serviceCollection,
object serviceKey,
IEmbeddingGenerator<TInput, TEmbedding> innerGenerator)
IEmbeddingGenerator<TInput, TEmbedding> innerGenerator,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TEmbedding : Embedding
=> AddKeyedEmbeddingGenerator(serviceCollection, serviceKey, _ => innerGenerator);
=> AddKeyedEmbeddingGenerator(serviceCollection, serviceKey, _ => innerGenerator, lifetime);

/// <summary>Registers a keyed singleton embedding generator in the <see cref="IServiceCollection"/>.</summary>
/// <typeparam name="TInput">The type from which embeddings will be generated.</typeparam>
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
/// <param name="serviceKey">The key with which to associated the generator.</param>
/// <param name="innerGeneratorFactory">A callback that produces the inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
/// <param name="lifetime">The service lifetime for the client.</param>
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
/// <remarks>The generator is registered as a singleton service.</remarks>
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddKeyedEmbeddingGenerator<TInput, TEmbedding>(
this IServiceCollection serviceCollection,
object serviceKey,
Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory)
Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory,
ServiceLifetime lifetime = ServiceLifetime.Singleton)
where TEmbedding : Embedding
{
_ = Throw.IfNull(serviceCollection);
_ = Throw.IfNull(serviceKey);
_ = Throw.IfNull(innerGeneratorFactory);

var builder = new EmbeddingGeneratorBuilder<TInput, TEmbedding>(innerGeneratorFactory);
_ = serviceCollection.AddKeyedSingleton(serviceKey, (services, _) => builder.Build(services));
serviceCollection.Add(new ServiceDescriptor(typeof(IEmbeddingGenerator<TInput, TEmbedding>), serviceKey, factory: (services, serviceKey) => builder.Build(services), lifetime));
return builder;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,96 @@ public void CanRegisterKeyedSingletonUsingSharedInstance()
Assert.IsType<TestChatClient>(instance.InnerClient);
}

[Theory]
[InlineData(null)]
[InlineData(ServiceLifetime.Singleton)]
[InlineData(ServiceLifetime.Scoped)]
[InlineData(ServiceLifetime.Transient)]
public void AddChatClient_RegistersExpectedLifetime(ServiceLifetime? lifetime)
{
ServiceCollection sc = new();
ServiceLifetime expectedLifetime = lifetime ?? ServiceLifetime.Singleton;
ChatClientBuilder builder = lifetime.HasValue
? sc.AddChatClient(services => new TestChatClient(), lifetime.Value)
: sc.AddChatClient(services => new TestChatClient());

ServiceDescriptor sd = Assert.Single(sc);
Assert.Equal(typeof(IChatClient), sd.ServiceType);
Assert.False(sd.IsKeyedService);
Assert.Null(sd.ImplementationInstance);
Assert.NotNull(sd.ImplementationFactory);
Assert.IsType<TestChatClient>(sd.ImplementationFactory(null!));
Assert.Equal(expectedLifetime, sd.Lifetime);
}

[Theory]
[InlineData(null)]
[InlineData(ServiceLifetime.Singleton)]
[InlineData(ServiceLifetime.Scoped)]
[InlineData(ServiceLifetime.Transient)]
public void AddKeyedChatClient_RegistersExpectedLifetime(ServiceLifetime? lifetime)
{
ServiceCollection sc = new();
ServiceLifetime expectedLifetime = lifetime ?? ServiceLifetime.Singleton;
ChatClientBuilder builder = lifetime.HasValue
? sc.AddKeyedChatClient("key", services => new TestChatClient(), lifetime.Value)
: sc.AddKeyedChatClient("key", services => new TestChatClient());

ServiceDescriptor sd = Assert.Single(sc);
Assert.Equal(typeof(IChatClient), sd.ServiceType);
Assert.True(sd.IsKeyedService);
Assert.Equal("key", sd.ServiceKey);
Assert.Null(sd.KeyedImplementationInstance);
Assert.NotNull(sd.KeyedImplementationFactory);
Assert.IsType<TestChatClient>(sd.KeyedImplementationFactory(null!, null!));
Assert.Equal(expectedLifetime, sd.Lifetime);
}

[Theory]
[InlineData(null)]
[InlineData(ServiceLifetime.Singleton)]
[InlineData(ServiceLifetime.Scoped)]
[InlineData(ServiceLifetime.Transient)]
public void AddEmbeddingGenerator_RegistersExpectedLifetime(ServiceLifetime? lifetime)
{
ServiceCollection sc = new();
ServiceLifetime expectedLifetime = lifetime ?? ServiceLifetime.Singleton;
var builder = lifetime.HasValue
? sc.AddEmbeddingGenerator(services => new TestEmbeddingGenerator(), lifetime.Value)
: sc.AddEmbeddingGenerator(services => new TestEmbeddingGenerator());

ServiceDescriptor sd = Assert.Single(sc);
Assert.Equal(typeof(IEmbeddingGenerator<string, Embedding<float>>), sd.ServiceType);
Assert.False(sd.IsKeyedService);
Assert.Null(sd.ImplementationInstance);
Assert.NotNull(sd.ImplementationFactory);
Assert.IsType<TestEmbeddingGenerator>(sd.ImplementationFactory(null!));
Assert.Equal(expectedLifetime, sd.Lifetime);
}

[Theory]
[InlineData(null)]
[InlineData(ServiceLifetime.Singleton)]
[InlineData(ServiceLifetime.Scoped)]
[InlineData(ServiceLifetime.Transient)]
public void AddKeyedEmbeddingGenerator_RegistersExpectedLifetime(ServiceLifetime? lifetime)
{
ServiceCollection sc = new();
ServiceLifetime expectedLifetime = lifetime ?? ServiceLifetime.Singleton;
var builder = lifetime.HasValue
? sc.AddKeyedEmbeddingGenerator("key", services => new TestEmbeddingGenerator(), lifetime.Value)
: sc.AddKeyedEmbeddingGenerator("key", services => new TestEmbeddingGenerator());

ServiceDescriptor sd = Assert.Single(sc);
Assert.Equal(typeof(IEmbeddingGenerator<string, Embedding<float>>), sd.ServiceType);
Assert.True(sd.IsKeyedService);
Assert.Equal("key", sd.ServiceKey);
Assert.Null(sd.KeyedImplementationInstance);
Assert.NotNull(sd.KeyedImplementationFactory);
Assert.IsType<TestEmbeddingGenerator>(sd.KeyedImplementationFactory(null!, null!));
Assert.Equal(expectedLifetime, sd.Lifetime);
}

public class SingletonMiddleware(IChatClient inner, IServiceProvider services) : DelegatingChatClient(inner)
{
public new IChatClient InnerClient => base.InnerClient;
Expand Down