Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -19,9 +19,10 @@ public static class AgentHostingServiceCollectionExtensions
/// <param name="services">The service collection to configure.</param>
/// <param name="name">The name of the agent.</param>
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The same <see cref="IServiceCollection"/> instance so that additional calls can be chained.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="name"/> is <see langword="null"/>.</exception>
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions)
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(services);
Throw.IfNullOrEmpty(name);
Expand All @@ -30,7 +31,7 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
var chatClient = sp.GetRequiredService<IChatClient>();
var tools = sp.GetKeyedServices<AITool>(name).ToList();
return new ChatClientAgent(chatClient, instructions, key, tools: tools);
});
}, lifetime);
}

/// <summary>
Expand All @@ -40,17 +41,18 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
/// <param name="name">The name of the agent.</param>
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="chatClient">The chat client which the agent will use for inference.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The same <see cref="IServiceCollection"/> instance so that additional calls can be chained.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="name"/> is <see langword="null"/>.</exception>
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, IChatClient chatClient)
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, IChatClient chatClient, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(services);
Throw.IfNullOrEmpty(name);
return services.AddAIAgent(name, (sp, key) =>
{
var tools = sp.GetKeyedServices<AITool>(name).ToList();
return new ChatClientAgent(chatClient, instructions, key, tools: tools);
});
}, lifetime);
}

/// <summary>
Expand All @@ -60,9 +62,10 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
/// <param name="name">The name of the agent.</param>
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="chatClientServiceKey">The key to use when resolving the chat client from the service provider. If <see langword="null"/>, a non-keyed service will be resolved.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The same <see cref="IServiceCollection"/> instance so that additional calls can be chained.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="name"/> is <see langword="null"/>.</exception>
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, object? chatClientServiceKey)
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, object? chatClientServiceKey, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(services);
Throw.IfNullOrEmpty(name);
Expand All @@ -71,7 +74,7 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
var chatClient = chatClientServiceKey is null ? sp.GetRequiredService<IChatClient>() : sp.GetRequiredKeyedService<IChatClient>(chatClientServiceKey);
var tools = sp.GetKeyedServices<AITool>(name).ToList();
return new ChatClientAgent(chatClient, instructions, key, tools: tools);
});
}, lifetime);
}

/// <summary>
Expand All @@ -82,9 +85,10 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="description">A description of the agent.</param>
/// <param name="chatClientServiceKey">The key to use when resolving the chat client from the service provider. If <see langword="null"/>, a non-keyed service will be resolved.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The same <see cref="IServiceCollection"/> instance so that additional calls can be chained.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/> or <paramref name="name"/> is <see langword="null"/>.</exception>
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, string? description, object? chatClientServiceKey)
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, string? instructions, string? description, object? chatClientServiceKey, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(services);
Throw.IfNullOrEmpty(name);
Expand All @@ -93,7 +97,7 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
var chatClient = chatClientServiceKey is null ? sp.GetRequiredService<IChatClient>() : sp.GetRequiredKeyedService<IChatClient>(chatClientServiceKey);
var tools = sp.GetKeyedServices<AITool>(name).ToList();
return new ChatClientAgent(chatClient, instructions: instructions, name: key, description: description, tools: tools);
});
}, lifetime);
}

/// <summary>
Expand All @@ -102,15 +106,16 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
/// <param name="services">The service collection to configure.</param>
/// <param name="name">The name of the agent.</param>
/// <param name="createAgentDelegate">A factory delegate that creates the AI agent instance. The delegate receives the service provider and agent key as parameters.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The same <see cref="IServiceCollection"/> instance so that additional calls can be chained.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services"/>, <paramref name="name"/>, or <paramref name="createAgentDelegate"/> is <see langword="null"/>.</exception>
/// <exception cref="InvalidOperationException">Thrown when the agent factory delegate returns <see langword="null"/> or an agent whose <see cref="AIAgent.Name"/> does not match <paramref name="name"/>.</exception>
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, Func<IServiceProvider, string, AIAgent> createAgentDelegate)
public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, string name, Func<IServiceProvider, string, AIAgent> createAgentDelegate, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(services);
Throw.IfNull(name);
Throw.IfNull(createAgentDelegate);
services.AddKeyedSingleton(name, (sp, key) =>
services.AddKeyedService(name, (sp, key) =>
{
Throw.IfNull(key);
var keyString = key as string;
Expand All @@ -122,8 +127,18 @@ public static IHostedAgentBuilder AddAIAgent(this IServiceCollection services, s
}

return agent;
});
}, lifetime);

return new HostedAgentBuilder(name, services);
return new HostedAgentBuilder(name, services, lifetime);
}

/// <summary>
/// Registers a keyed service with the specified lifetime.
/// </summary>
internal static void AddKeyedService<T>(this IServiceCollection services, object? serviceKey, Func<IServiceProvider, object?, T> factory, ServiceLifetime lifetime)
where T : class
{
var descriptor = new ServiceDescriptor(typeof(T), serviceKey, (sp, key) => factory(sp, key), lifetime);
services.Add(descriptor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

using System;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Shared.Diagnostics;

Expand All @@ -18,12 +19,13 @@ public static class HostApplicationBuilderAgentExtensions
/// <param name="builder">The host application builder to configure.</param>
/// <param name="name">The name of the agent.</param>
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The configured host application builder.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/>, <paramref name="name"/>, or <paramref name="instructions"/> is null.</exception>
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions)
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(builder);
return builder.Services.AddAIAgent(name, instructions);
return builder.Services.AddAIAgent(name, instructions, lifetime);
}

/// <summary>
Expand All @@ -33,13 +35,14 @@ public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builde
/// <param name="name">The name of the agent.</param>
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="chatClient">The chat client which the agent will use for inference.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The configured host application builder.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/>, <paramref name="name"/>, or <paramref name="instructions"/> is null.</exception>
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, IChatClient chatClient)
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, IChatClient chatClient, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(builder);
Throw.IfNullOrEmpty(name);
return builder.Services.AddAIAgent(name, instructions, chatClient);
return builder.Services.AddAIAgent(name, instructions, chatClient, lifetime);
}

/// <summary>
Expand All @@ -50,13 +53,14 @@ public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builde
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="description">A description of the agent.</param>
/// <param name="chatClientServiceKey">The key to use when resolving the chat client from the service provider. If null, a non-keyed service will be resolved.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The configured host application builder.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/>, <paramref name="name"/>, or <paramref name="instructions"/> is null.</exception>
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, string? description, object? chatClientServiceKey)
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, string? description, object? chatClientServiceKey, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(builder);
Throw.IfNullOrEmpty(name);
return builder.Services.AddAIAgent(name, instructions, description, chatClientServiceKey);
return builder.Services.AddAIAgent(name, instructions, description, chatClientServiceKey, lifetime);
}

/// <summary>
Expand All @@ -66,12 +70,13 @@ public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builde
/// <param name="name">The name of the agent.</param>
/// <param name="instructions">The instructions for the agent.</param>
/// <param name="chatClientServiceKey">The key to use when resolving the chat client from the service provider. If null, a non-keyed service will be resolved.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The configured host application builder.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/>, <paramref name="name"/>, or <paramref name="instructions"/> is null.</exception>
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, object? chatClientServiceKey)
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, string? instructions, object? chatClientServiceKey, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(builder);
return builder.Services.AddAIAgent(name, instructions, chatClientServiceKey);
return builder.Services.AddAIAgent(name, instructions, chatClientServiceKey, lifetime);
}

/// <summary>
Expand All @@ -80,12 +85,13 @@ public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builde
/// <param name="builder">The host application builder to configure.</param>
/// <param name="name">The name of the agent.</param>
/// <param name="createAgentDelegate">A factory delegate that creates the AI agent instance. The delegate receives the service provider and agent key as parameters.</param>
/// <param name="lifetime">The DI service lifetime for the agent registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>The configured host application builder.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/>, <paramref name="name"/>, or <paramref name="createAgentDelegate"/> is null.</exception>
/// <exception cref="InvalidOperationException">Thrown when the agent factory delegate returns null or an invalid AI agent instance.</exception>
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, Func<IServiceProvider, string, AIAgent> createAgentDelegate)
public static IHostedAgentBuilder AddAIAgent(this IHostApplicationBuilder builder, string name, Func<IServiceProvider, string, AIAgent> createAgentDelegate, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(builder);
return builder.Services.AddAIAgent(name, createAgentDelegate);
return builder.Services.AddAIAgent(name, createAgentDelegate, lifetime);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,20 @@ public static class HostApplicationBuilderWorkflowExtensions
/// <param name="builder">The <see cref="IHostApplicationBuilder"/> to configure.</param>
/// <param name="name">The unique name for the workflow.</param>
/// <param name="createWorkflowDelegate">A factory function that creates the <see cref="Workflow"/> instance. The function receives the service provider and workflow name as parameters.</param>
/// <param name="lifetime">The DI service lifetime for the workflow registration. Defaults to <see cref="ServiceLifetime.Singleton"/>.</param>
/// <returns>An <see cref="IHostedWorkflowBuilder"/> that can be used to further configure the workflow.</returns>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="builder"/>, <paramref name="name"/>, or <paramref name="createWorkflowDelegate"/> is null.</exception>
/// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is empty.</exception>
/// <exception cref="InvalidOperationException">
/// Thrown when the factory delegate returns null or a workflow with a name that doesn't match the expected name.
/// </exception>
public static IHostedWorkflowBuilder AddWorkflow(this IHostApplicationBuilder builder, string name, Func<IServiceProvider, string, Workflow> createWorkflowDelegate)
public static IHostedWorkflowBuilder AddWorkflow(this IHostApplicationBuilder builder, string name, Func<IServiceProvider, string, Workflow> createWorkflowDelegate, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
Throw.IfNull(builder);
Throw.IfNull(name);
Throw.IfNull(createWorkflowDelegate);

builder.Services.AddKeyedSingleton(name, (sp, key) =>
builder.Services.AddKeyedService(name, (sp, key) =>
{
Throw.IfNull(key);
var keyString = key as string;
Expand All @@ -43,7 +44,7 @@ public static IHostedWorkflowBuilder AddWorkflow(this IHostApplicationBuilder bu
}

return workflow;
});
}, lifetime);

return new HostedWorkflowBuilder(name, builder);
}
Expand Down
8 changes: 5 additions & 3 deletions dotnet/src/Microsoft.Agents.AI.Hosting/HostedAgentBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ internal sealed class HostedAgentBuilder : IHostedAgentBuilder
{
public string Name { get; }
public IServiceCollection ServiceCollection { get; }
public ServiceLifetime Lifetime { get; }

public HostedAgentBuilder(string name, IHostApplicationBuilder builder)
: this(name, builder.Services)
public HostedAgentBuilder(string name, IHostApplicationBuilder builder, ServiceLifetime lifetime = ServiceLifetime.Singleton)
: this(name, builder.Services, lifetime)
{
}

public HostedAgentBuilder(string name, IServiceCollection serviceCollection)
public HostedAgentBuilder(string name, IServiceCollection serviceCollection, ServiceLifetime lifetime = ServiceLifetime.Singleton)
{
this.Name = name;
this.ServiceCollection = serviceCollection;
this.Lifetime = lifetime;
}
}
Loading
Loading